Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like RestActionReader 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 RestActionReader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class RestActionReader |
||
32 | { |
||
33 | const COLLECTION_ROUTE_PREFIX = 'c'; |
||
34 | |||
35 | /** |
||
36 | * @var Reader |
||
37 | */ |
||
38 | private $annotationReader; |
||
39 | |||
40 | /** |
||
41 | * @var ParamReaderInterface |
||
42 | */ |
||
43 | private $paramReader; |
||
44 | |||
45 | /** |
||
46 | * @var InflectorInterface |
||
47 | */ |
||
48 | private $inflector; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | private $formats; |
||
54 | |||
55 | /** |
||
56 | * @var bool |
||
57 | */ |
||
58 | private $includeFormat; |
||
59 | |||
60 | /** |
||
61 | * @var string|null |
||
62 | */ |
||
63 | private $routePrefix; |
||
64 | |||
65 | /** |
||
66 | * @var string|null |
||
67 | */ |
||
68 | private $namePrefix; |
||
69 | |||
70 | /** |
||
71 | * @var array|string|null |
||
72 | */ |
||
73 | private $versions; |
||
74 | |||
75 | /** |
||
76 | * @var bool|null |
||
77 | */ |
||
78 | private $pluralize; |
||
79 | |||
80 | /** |
||
81 | * @var array |
||
82 | */ |
||
83 | private $parents = []; |
||
84 | |||
85 | /** |
||
86 | * @var array |
||
87 | */ |
||
88 | private $availableHTTPMethods = [ |
||
89 | 'get', |
||
90 | 'post', |
||
91 | 'put', |
||
92 | 'patch', |
||
93 | 'delete', |
||
94 | 'link', |
||
95 | 'unlink', |
||
96 | 'head', |
||
97 | 'options', |
||
98 | 'mkcol', |
||
99 | 'propfind', |
||
100 | 'proppatch', |
||
101 | 'move', |
||
102 | 'copy', |
||
103 | 'lock', |
||
104 | 'unlock', |
||
105 | ]; |
||
106 | |||
107 | /** |
||
108 | * @var array |
||
109 | */ |
||
110 | private $availableConventionalActions = ['new', 'edit', 'remove']; |
||
111 | |||
112 | /** |
||
113 | * @var bool |
||
114 | */ |
||
115 | private $hasMethodPrefix; |
||
116 | |||
117 | 56 | /** |
|
118 | * Initializes controller reader. |
||
119 | 56 | * |
|
120 | 56 | * @param Reader $annotationReader |
|
121 | 56 | * @param ParamReaderInterface $paramReader |
|
122 | 56 | * @param InflectorInterface $inflector |
|
123 | 56 | * @param bool $includeFormat |
|
124 | 56 | * @param array $formats |
|
125 | * @param bool $hasMethodPrefix |
||
126 | */ |
||
127 | public function __construct(Reader $annotationReader, ParamReaderInterface $paramReader, InflectorInterface $inflector, $includeFormat, array $formats = [], $hasMethodPrefix = true) |
||
136 | |||
137 | /** |
||
138 | * Sets routes prefix. |
||
139 | * |
||
140 | * @param string $prefix Routes prefix |
||
141 | 37 | */ |
|
142 | public function setRoutePrefix($prefix = null) |
||
146 | |||
147 | /** |
||
148 | * Returns route prefix. |
||
149 | * |
||
150 | * @return string |
||
151 | 37 | */ |
|
152 | public function getRoutePrefix() |
||
156 | |||
157 | /** |
||
158 | * Sets route names prefix. |
||
159 | * |
||
160 | * @param string $prefix Route names prefix |
||
161 | */ |
||
162 | public function setNamePrefix($prefix = null) |
||
166 | |||
167 | /** |
||
168 | * Returns name prefix. |
||
169 | * |
||
170 | * @return string |
||
171 | 37 | */ |
|
172 | public function getNamePrefix() |
||
176 | |||
177 | /** |
||
178 | * Sets route names versions. |
||
179 | * |
||
180 | * @param array|string|null $versions Route names versions |
||
181 | */ |
||
182 | public function setVersions($versions = null) |
||
186 | |||
187 | /** |
||
188 | * Returns versions. |
||
189 | * |
||
190 | * @return array|null |
||
191 | 37 | */ |
|
192 | public function getVersions() |
||
196 | |||
197 | /** |
||
198 | * Sets pluralize. |
||
199 | * |
||
200 | * @param bool|null $pluralize Specify if resource name must be pluralized |
||
201 | */ |
||
202 | public function setPluralize($pluralize) |
||
206 | |||
207 | /** |
||
208 | * Returns pluralize. |
||
209 | * |
||
210 | * @return bool|null |
||
211 | 37 | */ |
|
212 | public function getPluralize() |
||
216 | |||
217 | /** |
||
218 | * Set parent routes. |
||
219 | * |
||
220 | * @param array $parents Array of parent resources names |
||
221 | */ |
||
222 | public function setParents(array $parents) |
||
226 | |||
227 | /** |
||
228 | * Returns parents. |
||
229 | * |
||
230 | * @return array |
||
231 | */ |
||
232 | public function getParents() |
||
236 | |||
237 | 37 | /** |
|
238 | * Reads action route. |
||
239 | * |
||
240 | 37 | * @param RestRouteCollection $collection |
|
241 | 5 | * @param \ReflectionMethod $method |
|
242 | * @param string[] $resource |
||
243 | * |
||
244 | * @throws \InvalidArgumentException |
||
245 | * |
||
246 | * @return Route |
||
247 | 37 | */ |
|
248 | public function read(RestRouteCollection $collection, \ReflectionMethod $method, $resource) |
||
350 | |||
351 | /** |
||
352 | 11 | * @return string|null |
|
353 | */ |
||
354 | private function getVersionCondition() |
||
362 | |||
363 | 18 | /** |
|
364 | 7 | * @param string|null $conditionOne |
|
365 | * @param string|null $conditionTwo |
||
366 | * |
||
367 | 11 | * @return string|null |
|
368 | 11 | */ |
|
369 | private function combineConditions($conditionOne, $conditionTwo) |
||
381 | |||
382 | 37 | /** |
|
383 | 37 | * Include the format in the path and requirements if its enabled. |
|
384 | * |
||
385 | 37 | * @param string $path |
|
386 | 12 | * @param array $requirements |
|
387 | 12 | */ |
|
388 | 37 | private function includeFormatIfNeeded(&$path, &$requirements) |
|
398 | 37 | ||
399 | /** |
||
400 | * Checks whether provided method is readable. |
||
401 | 37 | * |
|
402 | 10 | * @param \ReflectionMethod $method |
|
403 | * |
||
404 | * @return bool |
||
405 | 37 | */ |
|
406 | 37 | private function isMethodReadable(\ReflectionMethod $method) |
|
427 | |||
428 | 37 | /** |
|
429 | * Returns HTTP method and resources list from method signature. |
||
430 | * |
||
431 | 37 | * @param \ReflectionMethod $method |
|
432 | 35 | * @param string[] $resource |
|
433 | * |
||
434 | * @return bool|array |
||
435 | 37 | */ |
|
436 | 37 | private function getHttpMethodAndResourcesFromMethod(\ReflectionMethod $method, $resource) |
|
469 | 37 | ||
470 | /** |
||
471 | * Returns readable arguments from method. |
||
472 | 37 | * |
|
473 | * @param \ReflectionMethod $method |
||
474 | * |
||
475 | * @return \ReflectionParameter[] |
||
476 | 37 | */ |
|
477 | 37 | private function getMethodArguments(\ReflectionMethod $method) |
|
527 | |||
528 | 37 | /** |
|
529 | * Generates final resource name. |
||
530 | 37 | * |
|
531 | 37 | * @param string|bool $resource |
|
532 | 37 | * |
|
533 | 37 | * @return string |
|
534 | 37 | */ |
|
535 | 37 | private function generateResourceName($resource) |
|
543 | |||
544 | /** |
||
545 | * Generates route name from resources list. |
||
546 | * |
||
547 | * @param string[] $resources |
||
548 | * |
||
549 | 37 | * @return string |
|
550 | */ |
||
551 | 37 | private function generateRouteName(array $resources) |
|
562 | 34 | ||
563 | 24 | /** |
|
564 | 24 | * Generates URL parts for route from resources list. |
|
565 | 24 | * |
|
566 | 24 | * @param string[] $resources |
|
567 | 10 | * @param \ReflectionParameter[] $arguments |
|
568 | * @param string $httpMethod |
||
569 | 37 | * |
|
570 | 36 | * @return array |
|
571 | */ |
||
572 | 35 | private function generateUrlParts(array $resources, array $arguments, $httpMethod) |
|
606 | |||
607 | 24 | /** |
|
608 | * Returns custom HTTP method for provided list of resources, arguments, method. |
||
609 | * |
||
610 | * @param string $httpMethod current HTTP method |
||
611 | * @param string[] $resources resources list |
||
612 | * @param \ReflectionParameter[] $arguments list of method arguments |
||
613 | * |
||
614 | * @return string |
||
615 | */ |
||
616 | private function getCustomHttpMethod($httpMethod, array $resources, array $arguments) |
||
632 | |||
633 | /** |
||
634 | * Returns first route annotation for method. |
||
635 | * |
||
636 | 37 | * @param \ReflectionMethod $reflectionMethod |
|
637 | * |
||
638 | 37 | * @return RouteAnnotation[] |
|
639 | */ |
||
640 | 37 | private function readRouteAnnotation(\ReflectionMethod $reflectionMethod) |
|
650 | |||
651 | /** |
||
652 | * Reads class annotations. |
||
653 | 37 | * |
|
654 | * @param \ReflectionClass $reflectionClass |
||
655 | 37 | * @param string $annotationName |
|
656 | * |
||
657 | 37 | * @return RouteAnnotation|null |
|
658 | 18 | */ |
|
659 | private function readClassAnnotation(\ReflectionClass $reflectionClass, $annotationName) |
||
667 | |||
668 | /** |
||
669 | * Reads method annotations. |
||
670 | 37 | * |
|
671 | * @param \ReflectionMethod $reflectionMethod |
||
672 | 37 | * @param string $annotationName |
|
673 | 37 | * |
|
674 | * @return RouteAnnotation|null |
||
675 | 37 | */ |
|
676 | 18 | private function readMethodAnnotation(\ReflectionMethod $reflectionMethod, $annotationName) |
|
684 | |||
685 | /** |
||
686 | * Reads method annotations. |
||
687 | * |
||
688 | * @param \ReflectionMethod $reflectionMethod |
||
689 | * @param string $annotationName |
||
690 | * |
||
691 | * @return RouteAnnotation[] |
||
692 | */ |
||
693 | private function readMethodAnnotations(\ReflectionMethod $reflectionMethod, $annotationName) |
||
708 | 37 | ||
709 | 4 | /** |
|
710 | 4 | * @param RestRouteCollection $collection |
|
711 | 4 | * @param string $routeName |
|
712 | 4 | * @param Route $route |
|
713 | 4 | * @param bool $isCollection |
|
714 | 35 | * @param bool $isInflectable |
|
715 | * @param RouteAnnotation $annotation |
||
716 | 37 | */ |
|
717 | private function addRoute(RestRouteCollection $collection, $routeName, $route, $isCollection, $isInflectable, RouteAnnotation $annotation = null) |
||
740 | } |
||
741 |