Complex classes like EagerLoader 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 EagerLoader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class EagerLoader { |
||
10 | |||
11 | private static $instances = array(); // @codingStandardsIgnoreLine |
||
12 | |||
13 | private $id; // @codingStandardsIgnoreLine |
||
14 | |||
15 | private $metas = array(); // @codingStandardsIgnoreLine |
||
16 | |||
17 | private $containOptions = array( // @codingStandardsIgnoreLine |
||
18 | 'conditions' => 1, |
||
19 | 'fields' => 1, |
||
20 | 'order' => 1, |
||
21 | 'limit' => 1, |
||
22 | 'offset' => 1, |
||
23 | ); |
||
24 | |||
25 | /** |
||
26 | * Constructor |
||
27 | */ |
||
28 | public function __construct() { |
||
38 | |||
39 | /** |
||
40 | * Handles beforeFind event |
||
41 | * |
||
42 | * @param Model $model Model |
||
43 | * @param array $query Query |
||
44 | * @return array Modified query |
||
45 | */ |
||
46 | public static function handleBeforeFind(Model $model, $query) { |
||
61 | |||
62 | /** |
||
63 | * Gabage collection |
||
64 | * |
||
65 | * @param Model $model Model |
||
66 | * @return void |
||
67 | */ |
||
68 | private function collectGarbage(Model $model) { // @codingStandardsIgnoreLine |
||
84 | |||
85 | /** |
||
86 | * Handles afterFind event |
||
87 | * |
||
88 | * @param Model $model Model |
||
89 | * @param array $results Results |
||
90 | * @return array Modified results |
||
91 | * @throws UnexpectedValueException |
||
92 | */ |
||
93 | public static function handleAfterFind(Model $model, $results) { |
||
109 | |||
110 | /** |
||
111 | * Modifies the passed query to fetch the top level attachable associations. |
||
112 | * |
||
113 | * @param Model $model Model |
||
114 | * @param array $query Query |
||
115 | * @return array Modified query |
||
116 | */ |
||
117 | private function transformQuery(Model $model, array $query) { // @codingStandardsIgnoreLine |
||
133 | |||
134 | /** |
||
135 | * Modifies the results |
||
136 | * |
||
137 | * @param Model $model Model |
||
138 | * @param array $results Results |
||
139 | * @return array Modified results |
||
140 | */ |
||
141 | private function transformResults(Model $model, array $results) { // @codingStandardsIgnoreLine |
||
147 | |||
148 | /** |
||
149 | * Modifies the query to fetch attachable associations. |
||
150 | * |
||
151 | * @param Model $model Model |
||
152 | * @param string $path The target path of the model, such as 'User.Article' |
||
153 | * @param array $query Query |
||
154 | * @return array Modified query |
||
155 | */ |
||
156 | private function attachAssociations(Model $model, $path, array $query) { // @codingStandardsIgnoreLine |
||
173 | |||
174 | /** |
||
175 | * Fetches meta data |
||
176 | * |
||
177 | * @param string $path Path of the association |
||
178 | * @return array |
||
179 | */ |
||
180 | private function metas($path) { // @codingStandardsIgnoreLine |
||
186 | |||
187 | /** |
||
188 | * Fetches external associations |
||
189 | * |
||
190 | * @param Model $model Model |
||
191 | * @param string $path The target path of the external primary model, such as 'User.Article' |
||
192 | * @param array $results The results of the parent model |
||
193 | * @return array |
||
194 | */ |
||
195 | protected function loadExternal(Model $model, $path, array $results) { // @codingStandardsIgnoreLine |
||
208 | |||
209 | /** |
||
210 | * Merges results of external associations of an external association |
||
211 | * |
||
212 | * @param Model $model Model |
||
213 | * @param array $results Results |
||
214 | * @param array $meta Meta data to be used for eager loading |
||
215 | * @return array |
||
216 | */ |
||
217 | private function mergeExternalExternal(Model $model, array $results, array $meta) { // @codingStandardsIgnoreLine |
||
293 | |||
294 | /** |
||
295 | * Merges results of external associations of an internal association |
||
296 | * |
||
297 | * @param Model $model Model |
||
298 | * @param array $results Results |
||
299 | * @param array $meta Meta data to be used for eager loading |
||
300 | * @return array |
||
301 | */ |
||
302 | private function mergeInternalExternal(Model $model, array $results, array $meta) { // @codingStandardsIgnoreLine |
||
334 | |||
335 | /** |
||
336 | * Merges associated result |
||
337 | * |
||
338 | * @param array $result Results |
||
339 | * @param array $assoc Associated results |
||
340 | * @param string $propertyPath Path of the results |
||
341 | * @return array |
||
342 | */ |
||
343 | private function mergeAssocResult(array $result, array $assoc, $propertyPath) { // @codingStandardsIgnoreLine |
||
346 | |||
347 | /** |
||
348 | * Reformat `contain` array |
||
349 | * |
||
350 | * @param array|string $contain The value of `contain` option of the query |
||
351 | * @return array |
||
352 | */ |
||
353 | private function reformatContain($contain) { // @codingStandardsIgnoreLine |
||
380 | |||
381 | /** |
||
382 | * Normalizes the query |
||
383 | * |
||
384 | * @param Model $model Model |
||
385 | * @param array $query Query |
||
386 | * @return array Normalized query |
||
387 | */ |
||
388 | private function normalizeQuery(Model $model, array $query) { // @codingStandardsIgnoreLine |
||
438 | |||
439 | /** |
||
440 | * Normalize field |
||
441 | * |
||
442 | * @param Model $model Model |
||
443 | * @param string $field Name of the field |
||
444 | * @return string |
||
445 | */ |
||
446 | private function normalizeField(Model $model, $field) { // @codingStandardsIgnoreLine |
||
457 | |||
458 | /** |
||
459 | * Modifies the query to apply joins. |
||
460 | * |
||
461 | * @param Model $target Model to be joined |
||
462 | * @param array $query Query |
||
463 | * @param string $joinType The type for join |
||
464 | * @param array $keys Key fields being used for join |
||
465 | * @param array $options Extra options for join |
||
466 | * @return array Modified query |
||
467 | */ |
||
468 | private function buildJoinQuery(Model $target, array $query, $joinType, array $keys, array $options) { // @codingStandardsIgnoreLine |
||
489 | |||
490 | /** |
||
491 | * Adds a field into the `fields` option of the query |
||
492 | * |
||
493 | * @param array $query Query |
||
494 | * @param string $field Name of the field |
||
495 | * @return Modified query |
||
496 | */ |
||
497 | private function addField(array $query, $field) { // @codingStandardsIgnoreLine |
||
503 | |||
504 | /** |
||
505 | * Parse the `contain` option of the query recursively |
||
506 | * |
||
507 | * @param Model $parent Parent model of the contained model |
||
508 | * @param string $alias Alias of the contained model |
||
509 | * @param array $contain Reformatted `contain` option for the deep associations |
||
510 | * @param array|null $context Context |
||
511 | * @return array |
||
512 | * @throws InvalidArgumentException |
||
513 | */ |
||
514 | private function parseContain(Model $parent, $alias, array $contain, $context = null) { // @codingStandardsIgnoreLine |
||
604 | |||
605 | /** |
||
606 | * Returns whether the target is external or not |
||
607 | * |
||
608 | * @param array $context Context |
||
609 | * @param array $meta Meta data to be used for eager loading |
||
610 | * @return bool |
||
611 | */ |
||
612 | private function isExternal(array $context, array $meta) { // @codingStandardsIgnoreLine |
||
642 | |||
643 | /** |
||
644 | * Returns where `limit` or `offset` option exists |
||
645 | * |
||
646 | * @param array $options Options |
||
647 | * @return bool |
||
648 | */ |
||
649 | private function hasLimitOffset($options) { // @codingStandardsIgnoreLine |
||
652 | |||
653 | /** |
||
654 | * Triggers afterFind() method |
||
655 | * |
||
656 | * @param Model $parent Model |
||
657 | * @param string $alias Alias |
||
658 | * @param array $results Results |
||
659 | * @return array |
||
660 | */ |
||
661 | private function filterResults(Model $parent, $alias, array $results) { // @codingStandardsIgnoreLine |
||
677 | } |
||
678 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.