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 Asset 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 Asset, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Anomaly\Streams\Platform\Asset; |
||
28 | class Asset |
||
29 | { |
||
30 | |||
31 | /** |
||
32 | * The public base directory. |
||
33 | * |
||
34 | * @var null |
||
35 | */ |
||
36 | protected $directory = null; |
||
37 | |||
38 | /** |
||
39 | * Groups of assets. Groups can |
||
40 | * be single files as well. |
||
41 | * |
||
42 | * @var array |
||
43 | */ |
||
44 | protected $collections = []; |
||
45 | |||
46 | /** |
||
47 | * The URL generator. |
||
48 | * |
||
49 | * @var UrlGenerator |
||
50 | */ |
||
51 | protected $url; |
||
52 | |||
53 | /** |
||
54 | * The HTML utility. |
||
55 | * |
||
56 | * @var HtmlBuilder |
||
57 | */ |
||
58 | protected $html; |
||
59 | |||
60 | /** |
||
61 | * The files system. |
||
62 | * |
||
63 | * @var Filesystem |
||
64 | */ |
||
65 | protected $files; |
||
66 | |||
67 | /** |
||
68 | * Asset path hints by namespace. |
||
69 | * |
||
70 | * 'module.users' => 'the/resources/path' |
||
71 | * |
||
72 | * @var AssetPaths |
||
73 | */ |
||
74 | protected $paths; |
||
75 | |||
76 | /** |
||
77 | * The asset parser utility. |
||
78 | * |
||
79 | * @var AssetParser |
||
80 | */ |
||
81 | protected $parser; |
||
82 | |||
83 | /** |
||
84 | * The theme collection. |
||
85 | * |
||
86 | * @var ThemeCollection |
||
87 | */ |
||
88 | protected $themes; |
||
89 | |||
90 | /** |
||
91 | * The mount manager. |
||
92 | * |
||
93 | * @var MountManager |
||
94 | */ |
||
95 | protected $manager; |
||
96 | |||
97 | /** |
||
98 | * The HTTP request. |
||
99 | * |
||
100 | * @var Request |
||
101 | */ |
||
102 | protected $request; |
||
103 | |||
104 | /** |
||
105 | * The stream application. |
||
106 | * |
||
107 | * @var Application |
||
108 | */ |
||
109 | protected $application; |
||
110 | |||
111 | /** |
||
112 | * The config repository. |
||
113 | * |
||
114 | * @var array |
||
115 | */ |
||
116 | protected $config; |
||
117 | |||
118 | /** |
||
119 | * Create a new Application instance. |
||
120 | * |
||
121 | * @param Application $application |
||
122 | * @param ThemeCollection $themes |
||
123 | * @param MountManager $manager |
||
124 | * @param AssetParser $parser |
||
125 | * @param Repository $config |
||
126 | * @param Filesystem $files |
||
127 | * @param AssetPaths $paths |
||
128 | * @param Request $request |
||
129 | * @param HtmlBuilder $html |
||
130 | * @param UrlGenerator $url |
||
131 | */ |
||
132 | View Code Duplication | public function __construct( |
|
|
|||
133 | Application $application, |
||
134 | ThemeCollection $themes, |
||
135 | MountManager $manager, |
||
136 | AssetParser $parser, |
||
137 | Repository $config, |
||
138 | Filesystem $files, |
||
139 | AssetPaths $paths, |
||
140 | Request $request, |
||
141 | HtmlBuilder $html, |
||
142 | UrlGenerator $url |
||
143 | ) { |
||
144 | $this->url = $url; |
||
145 | $this->html = $html; |
||
146 | $this->files = $files; |
||
147 | $this->paths = $paths; |
||
148 | $this->config = $config; |
||
149 | $this->themes = $themes; |
||
150 | $this->parser = $parser; |
||
151 | $this->manager = $manager; |
||
152 | $this->request = $request; |
||
153 | $this->application = $application; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Add an asset or glob pattern to an asset collection. |
||
158 | * |
||
159 | * This should support the asset being the collection |
||
160 | * and the asset (for single files) internally |
||
161 | * so asset.links / asset.scripts will work. |
||
162 | * |
||
163 | * @param $collection |
||
164 | * @param $file |
||
165 | * @param array $filters |
||
166 | * @return $this |
||
167 | * @throws \Exception |
||
168 | */ |
||
169 | public function add($collection, $file, array $filters = []) |
||
203 | |||
204 | /** |
||
205 | * Download a file and return it's path. |
||
206 | * |
||
207 | * @param $url |
||
208 | * @param int $ttl |
||
209 | * @param null $path |
||
210 | * @return null|string |
||
211 | */ |
||
212 | public function download($url, $ttl = 3600, $path = null) |
||
226 | |||
227 | /** |
||
228 | * Return the contents of a collection. |
||
229 | * |
||
230 | * @param $collection |
||
231 | * @param array $filters |
||
232 | * @return string |
||
233 | */ |
||
234 | public function inline($collection, array $filters = []) |
||
240 | |||
241 | /** |
||
242 | * Return the URL to a compiled asset collection. |
||
243 | * |
||
244 | * @param $collection |
||
245 | * @param array $filters |
||
246 | * @return string |
||
247 | */ |
||
248 | public function url($collection, array $filters = [], array $parameters = [], $secure = null) |
||
260 | |||
261 | /** |
||
262 | * Return the path to a compiled asset collection. |
||
263 | * |
||
264 | * @param $collection |
||
265 | * @param array $filters |
||
266 | * @return string |
||
267 | */ |
||
268 | public function path($collection, array $filters = []) |
||
276 | |||
277 | /** |
||
278 | * Return the asset path to a compiled asset collection. |
||
279 | * |
||
280 | * @param $collection |
||
281 | * @param array $filters |
||
282 | * @return string |
||
283 | */ |
||
284 | public function asset($collection, array $filters = []) |
||
292 | |||
293 | /** |
||
294 | * Return the script tag for a collection. |
||
295 | * |
||
296 | * @param $collection |
||
297 | * @param array $filters |
||
298 | * @param array $attributes |
||
299 | * @return string |
||
300 | */ |
||
301 | public function script($collection, array $filters = [], array $attributes = []) |
||
307 | |||
308 | /** |
||
309 | * Return the style tag for a collection. |
||
310 | * |
||
311 | * @param $collection |
||
312 | * @param array $filters |
||
313 | * @param array $attributes |
||
314 | * @return string |
||
315 | */ |
||
316 | View Code Duplication | public function style($collection, array $filters = [], array $attributes = []) |
|
326 | |||
327 | /** |
||
328 | * Return an array of script tags. |
||
329 | * |
||
330 | * @param $collection |
||
331 | * @param array $filters |
||
332 | * @param array $attributes |
||
333 | * @return array |
||
334 | */ |
||
335 | public function scripts($collection, array $filters = [], array $attributes = []) |
||
346 | |||
347 | /** |
||
348 | * Return an array of style tags. |
||
349 | * |
||
350 | * @param $collection |
||
351 | * @param array $filters |
||
352 | * @param array $attributes |
||
353 | * @return array |
||
354 | */ |
||
355 | View Code Duplication | public function styles($collection, array $filters = [], array $attributes = []) |
|
370 | |||
371 | /** |
||
372 | * Return an array of paths to an asset collection. |
||
373 | * |
||
374 | * This instead of combining the collection contents |
||
375 | * just returns an array of individual processed |
||
376 | * paths instead. |
||
377 | * |
||
378 | * @param $collection |
||
379 | * @param array $additionalFilters |
||
380 | * @return array |
||
381 | */ |
||
382 | public function paths($collection, array $additionalFilters = []) |
||
400 | |||
401 | /** |
||
402 | * Return an array of style URLs. |
||
403 | * |
||
404 | * @param $collection |
||
405 | * @param array $filters |
||
406 | * @param array $attributes |
||
407 | * @param null $secure |
||
408 | * @return array |
||
409 | */ |
||
410 | public function urls($collection, array $filters = [], array $attributes = [], $secure = null) |
||
419 | |||
420 | /** |
||
421 | * @param $collection |
||
422 | * @param $filters |
||
423 | * @return string |
||
424 | */ |
||
425 | protected function getPath($collection, $filters) |
||
449 | |||
450 | /** |
||
451 | * Return the collection path. This |
||
452 | * is primarily used to determine paths |
||
453 | * to single assets. |
||
454 | * |
||
455 | * @param $collection |
||
456 | * @return string |
||
457 | */ |
||
458 | public function getCollectionPath($collection) |
||
465 | |||
466 | /** |
||
467 | * Publish the collection of assets to the path. |
||
468 | * |
||
469 | * @param $path |
||
470 | * @param $collection |
||
471 | * @param $additionalFilters |
||
472 | */ |
||
473 | protected function publish($path, $collection, $additionalFilters) |
||
497 | |||
498 | /** |
||
499 | * Transform an array of filters to |
||
500 | * an array of Assetic filters. |
||
501 | * |
||
502 | * @param $filters |
||
503 | * @param $hint |
||
504 | * @return mixed |
||
505 | */ |
||
506 | protected function transformFilters($filters, $hint) |
||
640 | |||
641 | /** |
||
642 | * Add filters that we can assume based |
||
643 | * on the asset's file name. |
||
644 | * |
||
645 | * @param $file |
||
646 | * @param $filters |
||
647 | * @return array |
||
648 | */ |
||
649 | protected function addConvenientFilters($file, $filters) |
||
669 | |||
670 | /** |
||
671 | * Decide whether we need to publish the file |
||
672 | * to the path or not. |
||
673 | * |
||
674 | * @param $path |
||
675 | * @param $collection |
||
676 | * @param array $filters |
||
677 | * @return bool |
||
678 | */ |
||
679 | protected function shouldPublish($path, $collection, array $filters = []) |
||
725 | |||
726 | /** |
||
727 | * Add a namespace path hint. |
||
728 | * |
||
729 | * @param $namespace |
||
730 | * @param $path |
||
731 | * @return $this |
||
732 | */ |
||
733 | public function addPath($namespace, $path) |
||
739 | |||
740 | /** |
||
741 | * Set the public base directory. |
||
742 | * |
||
743 | * @param $directory |
||
744 | * @return $this |
||
745 | */ |
||
746 | public function setDirectory($directory) |
||
752 | |||
753 | /** |
||
754 | * Create asset collection from collection array |
||
755 | * |
||
756 | * @param $collection |
||
757 | * @param array $additionalFilters |
||
758 | * @return AssetCollection |
||
759 | */ |
||
760 | private function getAssetCollection($collection, $additionalFilters = []) |
||
784 | |||
785 | /** |
||
786 | * Return the filters used in a collection. |
||
787 | * |
||
788 | * @param $collection |
||
789 | * @param array $filters |
||
790 | * @return array |
||
791 | */ |
||
792 | protected function collectionFilters($collection, array $filters = []) |
||
798 | |||
799 | /** |
||
800 | * Return nothing. |
||
801 | * |
||
802 | * @return string |
||
803 | */ |
||
804 | public function __toString() |
||
808 | } |
||
809 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.