Complex classes like Query often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Query, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class Query implements \IteratorAggregate |
||
34 | { |
||
35 | public const TYPE_FIND = 1; |
||
36 | public const TYPE_FIND_AND_UPDATE = 2; |
||
37 | public const TYPE_FIND_AND_REMOVE = 3; |
||
38 | public const TYPE_INSERT = 4; |
||
39 | public const TYPE_UPDATE = 5; |
||
40 | public const TYPE_REMOVE = 6; |
||
41 | public const TYPE_GROUP = 7; |
||
42 | public const TYPE_MAP_REDUCE = 8; |
||
43 | public const TYPE_DISTINCT = 9; |
||
44 | public const TYPE_COUNT = 11; |
||
45 | |||
46 | /** |
||
47 | * @deprecated 1.1 Will be removed for 2.0 |
||
48 | */ |
||
49 | public const TYPE_GEO_LOCATION = 10; |
||
50 | |||
51 | public const HINT_REFRESH = 1; |
||
52 | // 2 was used for HINT_SLAVE_OKAY, which was removed in 2.0 |
||
53 | public const HINT_READ_PREFERENCE = 3; |
||
54 | public const HINT_READ_ONLY = 5; |
||
55 | |||
56 | /** |
||
57 | * The DocumentManager instance. |
||
58 | * |
||
59 | * @var DocumentManager |
||
60 | */ |
||
61 | private $dm; |
||
62 | |||
63 | /** |
||
64 | * The ClassMetadata instance. |
||
65 | * |
||
66 | * @var ClassMetadata |
||
67 | */ |
||
68 | private $class; |
||
69 | |||
70 | /** |
||
71 | * Whether to hydrate results as document class instances. |
||
72 | * |
||
73 | * @var bool |
||
74 | */ |
||
75 | private $hydrate = true; |
||
76 | |||
77 | /** |
||
78 | * Array of primer Closure instances. |
||
79 | * |
||
80 | * @var array |
||
81 | */ |
||
82 | private $primers = []; |
||
83 | |||
84 | /** |
||
85 | * Hints for UnitOfWork behavior. |
||
86 | * |
||
87 | * @var array |
||
88 | */ |
||
89 | private $unitOfWorkHints = []; |
||
90 | |||
91 | /** |
||
92 | * The Collection instance. |
||
93 | * |
||
94 | * @var Collection |
||
95 | */ |
||
96 | protected $collection; |
||
97 | |||
98 | /** |
||
99 | * Query structure generated by the Builder class. |
||
100 | * |
||
101 | * @var array |
||
102 | */ |
||
103 | private $query; |
||
104 | |||
105 | /** @var Iterator */ |
||
106 | private $iterator; |
||
107 | |||
108 | /** |
||
109 | * Query options |
||
110 | * |
||
111 | * @var array |
||
112 | */ |
||
113 | private $options; |
||
114 | |||
115 | /** |
||
116 | * |
||
117 | * |
||
118 | * Please note that $requireIndexes was deprecated in 1.2 and will be removed in 2.0 |
||
119 | * |
||
120 | * @param array $query |
||
121 | * @param array $options |
||
122 | * @param bool $hydrate |
||
123 | * @param bool $refresh |
||
124 | * @param array $primers |
||
125 | * @param bool $readOnly |
||
126 | */ |
||
127 | 161 | public function __construct(DocumentManager $dm, ClassMetadata $class, Collection $collection, array $query = [], array $options = [], $hydrate = true, $refresh = false, array $primers = [], $readOnly = false) |
|
173 | |||
174 | 64 | public function __clone() |
|
178 | |||
179 | /** |
||
180 | * Return an array of information about the query structure for debugging. |
||
181 | * |
||
182 | * The $name parameter may be used to return a specific key from the |
||
183 | * internal $query array property. If omitted, the entire array will be |
||
184 | * returned. |
||
185 | * |
||
186 | * @param string $name |
||
187 | * @return mixed |
||
188 | */ |
||
189 | 27 | public function debug($name = null) |
|
193 | |||
194 | /** |
||
195 | * Execute the query and returns the results. |
||
196 | * |
||
197 | * @throws MongoDBException |
||
198 | * @return Iterator|int|string|array |
||
199 | */ |
||
200 | 120 | public function execute() |
|
234 | |||
235 | /** |
||
236 | * Gets the ClassMetadata instance. |
||
237 | * |
||
238 | * @return ClassMetadata $class |
||
239 | */ |
||
240 | public function getClass() |
||
244 | |||
245 | /** |
||
246 | * Gets the DocumentManager instance. |
||
247 | * |
||
248 | * @return DocumentManager $dm |
||
249 | */ |
||
250 | public function getDocumentManager() |
||
254 | |||
255 | /** |
||
256 | * Execute the query and return its result, which must be an Iterator. |
||
257 | * |
||
258 | * If the query type is not expected to return an Iterator, |
||
259 | * BadMethodCallException will be thrown before executing the query. |
||
260 | * Otherwise, the query will be executed and UnexpectedValueException will |
||
261 | * be thrown if {@link Query::execute()} does not return an Iterator. |
||
262 | * |
||
263 | * @see http://php.net/manual/en/iteratoraggregate.getiterator.php |
||
264 | * @return Iterator |
||
265 | * @throws \BadMethodCallException If the query type would not return an Iterator. |
||
266 | * @throws \UnexpectedValueException If the query did not return an Iterator. |
||
267 | */ |
||
268 | 84 | public function getIterator() |
|
287 | |||
288 | /** |
||
289 | * Return the query structure. |
||
290 | * |
||
291 | * @return array |
||
292 | */ |
||
293 | 14 | public function getQuery() |
|
297 | |||
298 | /** |
||
299 | * Execute the query and return the first result. |
||
300 | * |
||
301 | * @return array|object|null |
||
302 | */ |
||
303 | 64 | public function getSingleResult() |
|
309 | |||
310 | /** |
||
311 | * Return the query type. |
||
312 | * |
||
313 | * @return int |
||
314 | */ |
||
315 | public function getType() |
||
319 | |||
320 | /** |
||
321 | * Sets whether or not to hydrate the documents to objects. |
||
322 | * |
||
323 | * @param bool $hydrate |
||
324 | */ |
||
325 | public function setHydrate($hydrate) |
||
329 | |||
330 | /** |
||
331 | * Set whether documents should be registered in UnitOfWork. If document would |
||
332 | * already be managed it will be left intact and new instance returned. |
||
333 | * |
||
334 | * This option has no effect if hydration is disabled. |
||
335 | * |
||
336 | * @param bool $readOnly |
||
337 | */ |
||
338 | 160 | public function setReadOnly($readOnly) |
|
342 | |||
343 | /** |
||
344 | * Set whether to refresh hydrated documents that are already in the |
||
345 | * identity map. |
||
346 | * |
||
347 | * This option has no effect if hydration is disabled. |
||
348 | * |
||
349 | * @param bool $refresh |
||
350 | */ |
||
351 | 160 | public function setRefresh($refresh) |
|
355 | |||
356 | /** |
||
357 | * Execute the query and return its results as an array. |
||
358 | * |
||
359 | * @see IteratorAggregate::toArray() |
||
360 | * @return array |
||
361 | */ |
||
362 | 11 | public function toArray() |
|
366 | |||
367 | /** |
||
368 | * Returns an array containing the specified keys and their values from the |
||
369 | * query array, provided they exist and are not null. |
||
370 | * |
||
371 | * @param string ...$keys One or more option keys to be read |
||
372 | * @return array |
||
373 | */ |
||
374 | 119 | private function getQueryOptions(string ...$keys) |
|
383 | |||
384 | 106 | private function makeIterator(Cursor $cursor): Iterator |
|
399 | |||
400 | /** |
||
401 | * Returns an array with its keys renamed based on the translation map. |
||
402 | * |
||
403 | * @param array $options Query options |
||
404 | * @return array $rename Translation map (from => to) for renaming keys |
||
405 | */ |
||
406 | 111 | private function renameQueryOptions(array $options, array $rename) |
|
422 | |||
423 | /** |
||
424 | * Execute the query and return its result. |
||
425 | * |
||
426 | * The return value will vary based on the query type. Commands with results |
||
427 | * (e.g. aggregate, inline mapReduce) may return an ArrayIterator. Other |
||
428 | * commands and operations may return a status array or a boolean, depending |
||
429 | * on the driver's write concern. Queries and some mapReduce commands will |
||
430 | * return an Iterator. |
||
431 | * |
||
432 | * @return Iterator|string|int|array |
||
433 | */ |
||
434 | 120 | public function runQuery() |
|
511 | } |
||
512 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.