@@ -21,20 +21,11 @@ class ModelCache {
2121 public static ?self $ instance = null ;
2222
2323 /**
24- * @var array $index An associative array that contains cache Model objects that have been loaded and
25- * indexed by specific fields for quick lookup. Structured as:
26- *
27- * [Model class name] => [
28- * [index field name] => [
29- * [index field value] => Model object
30- * ]
31- * ]
32- */
33- public static array $ index = [];
34-
35- /**
36- * @var array $cache An associative array that contains cached Model objects that have been loaded into memory as
37- * a complete ModelSet of every object of that Model type. Structured as: [Model class name] => ModelSet object
24+ * @var array $cache An associative array that contains cached ModelSet objects that have been loaded into memory.
25+ * This includes root ModelSets that contain all Model objects of a given Model class as well as indexed queries
26+ * that have already been run against those ModelSets. Structured as: [ModelSet signature => ModelSet object].
27+ * Please note that root ModelSets are indexed by their qualified Model class name only, whereas queried ModelSets
28+ * are indexed by the root signature followed by a series of query hashes separated by colons.
3829 */
3930 public static array $ cache = [];
4031
@@ -83,143 +74,10 @@ class ModelCache {
8374 return self ::$ cache [$ model_class ];
8475 }
8576
86- /**
87- * Raises an error if the given Model object does not support being indexed by the specified field.
88- * @param Model $model The Model object to check for uniqueness.
89- * @param string $index_field The index field name to check for uniqueness.
90- * @throws ServerError If the Model is attempting to be indexed by a non-unique field.
91- * @throws ServerError If the Model is not many-enabled.
92- */
93- private static function ensure_model_supports_indexing (Model $ model , string $ index_field ): void {
94- # Only many-enabled Models can be indexed
95- if (!$ model ->many ) {
96- throw new ServerError (
97- message: "Cannot index Model class ' " . $ model ->get_class_fqn () . 'because it is not many-enabled. ' ,
98- response_id: 'MODEL_CACHE_INDEX_FIELD_ON_NON_MANY_MODEL ' ,
99- );
100- }
101-
102- # Models with parent model classes cannot be indexed
103- if ($ model ->parent_model_class ) {
104- throw new ServerError (
105- message: "Cannot index Model class ' " .
106- $ model ->get_class_fqn () .
107- "' because it has a parent model class ' " .
108- $ model ->parent_model_class .
109- "'. " ,
110- response_id: 'MODEL_CACHE_INDEX_FIELD_ON_PARENTED_MODEL ' ,
111- );
112- }
113-
114- # If indexing by 'id', it's always unique
115- if ($ index_field === 'id ' ) {
116- return ;
117- }
118-
119- # Check if the index field is unique on the Model object
120- if (!$ model ->$ index_field ->unique ) {
121- throw new ServerError (
122- message: "Cannot index Model class ' " .
123- $ model ->get_class_fqn () .
124- "' by non-unique field " .
125- "' $ index_field'. " ,
126- response_id: 'MODEL_CACHE_INDEX_FIELD_NOT_UNIQUE ' ,
127- );
128- }
129- }
130-
131- /**
132- * Indexes the ModelSet cache for a given Model class by a specified field. This method will populate
133- * the $index array for the specified Model class and index field.
134- * @param string $model_class The Model class name whose ModelSet is to be indexed. If no cached ModelSet exists,
135- * one will be created by reading all Model objects from the data source.
136- * @param string $index_field The field name to index the Model objects by.
137- * @return array An associative array of indexed Model objects.
138- */
139- public static function index_modelset_by_field (string $ model_class , string $ index_field ): array {
140- # First, check if this Model class has already been indexed by this field
141- if (isset (self ::$ index [$ model_class ][$ index_field ])) {
142- return self ::$ index [$ model_class ][$ index_field ];
143- }
144-
145- # Ensure the Model can be indexed by the specified field
146- $ model = new $ model_class ();
147- self ::ensure_model_supports_indexing ($ model , $ index_field );
148-
149- # Fetch or create the ModelSet for this Model class
150- $ model_set = $ model ->read_all ();
151-
152- # Create an associative array to hold the indexed Model objects
153- $ indexed_models = [];
154-
155- # Index each Model object in the ModelSet by the specified field
156- foreach ($ model_set ->model_objects as $ model ) {
157- $ index_value = $ index_field === 'id ' ? $ model ->id : $ model ->$ index_field ->value ;
158- $ indexed_models [$ index_value ] = $ model ;
159- }
160-
161- # Store the indexed models in the ModelCache index and return them
162- self ::$ index [$ model_class ][$ index_field ] = $ indexed_models ;
163- return $ indexed_models ;
164- }
165-
166- /**
167- * Checks if a given Model class has a cached Model object by its index field/value.
168- * @param string $model_class The Model class name to check in the cache.
169- * @param string $index_field The index field name to look up the Model object by
170- * @param mixed $index_value The index field value to look up the Model object by
171- * @return bool True if a cached Model object exists for the specified Model class and index
172- */
173- public static function has_model (string $ model_class , string $ index_field = 'id ' , mixed $ index_value = null ): bool {
174- # Cache is always a miss if the Model class is not indexed
175- if (!self ::$ index [$ model_class ]) {
176- return false ;
177- }
178-
179- # Cache is a hit for non-many enabled models if a single Model object is indexed under the Model class
180- if (self ::$ index [$ model_class ] instanceof Model) {
181- return true ;
182- }
183-
184- # Otherwise, cache is only a hit for many enabled models if the index field/value exists in the index
185- return isset (self ::$ index [$ model_class ][$ index_field ][$ index_value ]);
186- }
187-
188- /**
189- * Fetches a cached Model object by its Model class name and index field/value.
190- * @param string $model_class The Model class name to load from the cache.
191- * @param string $index_field The index field name to look up the Model object by. Only for many enabled Models.
192- * @param mixed $index_value The index field value to look up the Model object by. Only for many enabled Models.
193- * @return Model The cached Model object
194- * @throws NotFoundError If no cached Model object exists for the specified Model class and index.
195- */
196- public static function fetch_model (
197- string $ model_class ,
198- string $ index_field = 'id ' ,
199- mixed $ index_value = null ,
200- ): Model {
201- if (!self ::has_model ($ model_class , $ index_field , $ index_value )) {
202- throw new NotFoundError (
203- message: "No cached Model found for Model class ' $ model_class' with " .
204- "index field ' $ index_field' and index value ' $ index_value'. " ,
205- response_id: 'MODEL_CACHE_MODEL_NOT_FOUND ' ,
206- );
207- }
208-
209- # For many enabled models, return the Model object indexed under the specified index field and value
210- if (isset (self ::$ index [$ model_class ][$ index_field ][$ index_value ])) {
211- return self ::$ index [$ model_class ][$ index_field ][$ index_value ];
212- }
213-
214- # Otherwise, return the Model object indexed under the Model class only
215- return self ::$ index [$ model_class ];
216- }
217-
21877 /**
21978 * Clears the ModelCache of all cached ModelSets and indexed Model objects.
22079 */
22180 public static function clear (): void {
222- self ::$ index = [];
22381 self ::$ cache = [];
22482 }
22583}
0 commit comments