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 AssetsParser 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 AssetsParser, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class AssetsParser |
||
18 | { |
||
19 | |||
20 | protected $files = []; |
||
21 | protected $hash = []; |
||
22 | protected $compiled_files; |
||
23 | protected $type; |
||
24 | protected $path; |
||
25 | protected $domains = []; |
||
26 | private $debug = false; |
||
27 | |||
28 | /** |
||
29 | * Constructor por defecto |
||
30 | * |
||
31 | * @param string $type |
||
32 | */ |
||
33 | 1 | public function __construct($type = 'js') |
|
40 | |||
41 | /** |
||
42 | * Método que calcula el path completo a copiar un recurso |
||
43 | * @param string $filename_path |
||
44 | * @param string[] $source |
||
45 | * @return string |
||
46 | */ |
||
47 | protected static function calculateResourcePathname($filename_path, $source) |
||
48 | { |
||
49 | $source_file = preg_replace("/'/", "", $source[1]); |
||
50 | View Code Duplication | if (preg_match('/\#/', $source_file)) { |
|
51 | $source_file = explode("#", $source_file); |
||
52 | $source_file = $source_file[0]; |
||
53 | } |
||
54 | View Code Duplication | if (preg_match('/\?/', $source_file)) { |
|
55 | $source_file = explode("?", $source_file); |
||
56 | $source_file = $source_file[0]; |
||
57 | } |
||
58 | $orig = realpath(dirname($filename_path) . DIRECTORY_SEPARATOR . $source_file); |
||
59 | return $orig; |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * Método que añade un nuevo fichero al proceso de generación de los assets |
||
64 | * @param $filename |
||
65 | * @return AssetsParser |
||
66 | * @internal param string $type |
||
67 | * |
||
68 | */ |
||
69 | 1 | public function addFile($filename) |
|
70 | { |
||
71 | 1 | if (file_exists($this->path . $filename) && preg_match('/\.' . $this->type . '$/i', $filename)) { |
|
72 | $this->files[] = $filename; |
||
73 | 1 | } elseif (!empty($this->domains)) { |
|
74 | foreach ($this->domains as $domain => $paths) { |
||
75 | $domain_filename = str_replace($domain, $paths["public"], $filename); |
||
76 | if (file_exists($domain_filename) && preg_match('/\.' . $this->type . '$/i', $domain_filename)) { |
||
77 | $this->files[] = $domain_filename; |
||
78 | } |
||
79 | } |
||
80 | } |
||
81 | 1 | return $this; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * Método que establece el hash con el que compilar los assets |
||
86 | * @param string $hash |
||
87 | * |
||
88 | * @return AssetsParser |
||
89 | */ |
||
90 | 1 | public function setHash($hash) |
|
96 | |||
97 | /** |
||
98 | * Método que procesa los ficheros solicitados en función del modo de ejecución |
||
99 | * @return AssetsParser |
||
100 | * @internal param string $type |
||
101 | * @throws ConfigException |
||
102 | */ |
||
103 | 1 | public function compile() |
|
119 | |||
120 | /** |
||
121 | * Método que compila los ficheros css y los procesa en función del modo de ejecución |
||
122 | * @return AssetsParser |
||
123 | * @throws ConfigException |
||
124 | */ |
||
125 | 1 | protected function compileCss() |
|
126 | { |
||
127 | 1 | $base = $this->path . "css" . DIRECTORY_SEPARATOR; |
|
128 | 1 | if ($this->debug || !file_exists($base . $this->hash . ".css")) { |
|
129 | 1 | $data = ''; |
|
130 | 1 | if (0 < count($this->files)) { |
|
131 | $minifier = new CSS(); |
||
132 | foreach ($this->files as $file) { |
||
133 | $data = $this->processCssLine($file, $base, $data); |
||
134 | } |
||
135 | } |
||
136 | 1 | if($this->debug) { |
|
137 | 1 | $this->storeContents($base . $this->hash . ".css", $data); |
|
138 | } else { |
||
139 | $minifier = new CSS(); |
||
140 | $minifier->add($data); |
||
141 | ini_set('max_execution_time', -1); |
||
142 | ini_set('memory_limit', -1); |
||
143 | GeneratorHelper::createDir($base); |
||
144 | $minifier->minify($base . $this->hash . ".css"); |
||
145 | unset($cssMinifier); |
||
146 | ini_restore('memory_limit'); |
||
147 | ini_restore('max_execution_time'); |
||
148 | } |
||
149 | } |
||
150 | 1 | return $this; |
|
151 | } |
||
152 | |||
153 | /** |
||
154 | * Método que compila los ficheros javascript en función del modo de ejecución |
||
155 | * @return $this |
||
156 | * @throws ConfigException |
||
157 | */ |
||
158 | 1 | protected function compileJs() |
|
159 | { |
||
160 | 1 | $base = $this->path . "js" . DIRECTORY_SEPARATOR; |
|
161 | 1 | if ($this->debug || !file_exists($base . $this->hash . ".js")) { |
|
162 | 1 | $data = ''; |
|
163 | 1 | if (0 < count($this->files)) { |
|
164 | $minifier = new JS(); |
||
165 | foreach ($this->files as $file) { |
||
166 | $path_parts = explode("/", $file); |
||
167 | if (file_exists($file)) { |
||
168 | if ($this->debug) { |
||
169 | $data = $this->putDebugJs($path_parts, $base, $file); |
||
170 | } elseif (!file_exists($base . $this->hash . ".js")) { |
||
171 | $minifier->add($file); |
||
172 | //$data = $this->putProductionJs($base, $file, $data); |
||
|
|||
173 | } |
||
174 | } |
||
175 | } |
||
176 | if($this->debug) { |
||
177 | $this->storeContents($base . $this->hash . ".js", $data); |
||
178 | } else { |
||
179 | ini_set('max_execution_time', -1); |
||
180 | ini_set('memory_limit', -1); |
||
181 | GeneratorHelper::createDir($base); |
||
182 | $minifier->minify($base . $this->hash . ".js"); |
||
183 | ini_restore('memory_limit'); |
||
184 | ini_restore('max_execution_time'); |
||
185 | } |
||
186 | unset($minifier); |
||
187 | } |
||
188 | } |
||
189 | 1 | return $this; |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * Método para guardar cualquier contenido y controlar que existe el directorio y se guarda correctamente |
||
194 | * @param string $path |
||
195 | * @param string $content |
||
196 | * @throws ConfigException |
||
197 | */ |
||
198 | 1 | View Code Duplication | private function storeContents($path, $content = "") |
199 | { |
||
200 | 1 | GeneratorHelper::createDir(dirname($path)); |
|
201 | 1 | if ("" !== $content && false === file_put_contents($path, $content)) { |
|
202 | throw new ConfigException(_('No se tienen permisos para escribir en ' . $path)); |
||
203 | } |
||
204 | 1 | } |
|
205 | |||
206 | /** |
||
207 | * Método que imprime el resultado de la generación de los assets |
||
208 | */ |
||
209 | 1 | public function printHtml() |
|
221 | |||
222 | /** |
||
223 | * Método que devuelve el html con la ruta compilada del recurso javascript |
||
224 | */ |
||
225 | 1 | View Code Duplication | protected function printJs() |
235 | |||
236 | /** |
||
237 | * Método que devuelve el html con la ruta compilada del recurso css |
||
238 | */ |
||
239 | 1 | View Code Duplication | protected function printCss() |
249 | |||
250 | /** |
||
251 | * @param string $source |
||
252 | * @param string $file |
||
253 | */ |
||
254 | protected function extractCssResources($source, $file) |
||
274 | |||
275 | /** |
||
276 | * Método que procesa cada línea de la hoja de estilos para copiar los recursos asociados |
||
277 | * @param string $file |
||
278 | * @param string $base |
||
279 | * @param string $data |
||
280 | * @return string |
||
281 | * @throws ConfigException |
||
282 | */ |
||
283 | protected function processCssLine($file, $base, $data) |
||
306 | |||
307 | /** |
||
308 | * @param $path_parts |
||
309 | * @param string $base |
||
310 | * @param $file |
||
311 | * @return string |
||
312 | * @throws ConfigException |
||
313 | */ |
||
314 | protected function putDebugJs($path_parts, $base, $file) |
||
325 | |||
326 | /** |
||
327 | * Servicio que busca el path para un dominio dado |
||
328 | * @param $string |
||
329 | * @param string $file_path |
||
330 | * |
||
331 | * @return string |
||
332 | */ |
||
333 | 1 | public static function findDomainPath($string, $file_path) |
|
334 | { |
||
335 | 1 | $domains = Template::getDomains(TRUE); |
|
336 | 1 | $filename_path = null; |
|
337 | 1 | View Code Duplication | if (!file_exists($file_path) && 0 < count($domains)) { |
338 | foreach ($domains as $domain => $paths) { |
||
339 | $domain_filename = str_replace($domain, $paths["public"], $string); |
||
340 | if (file_exists($domain_filename)) { |
||
341 | $filename_path = $domain_filename; |
||
342 | continue; |
||
343 | } |
||
344 | } |
||
345 | } |
||
346 | |||
347 | 1 | return $filename_path; |
|
348 | } |
||
349 | |||
350 | /** |
||
351 | * Método que calcula el path de un recurso web |
||
352 | * @param string $string |
||
353 | * @param string $name |
||
354 | * @param boolean $return |
||
355 | * @param string $filename_path |
||
356 | * |
||
357 | * @return string[] |
||
358 | */ |
||
359 | public static function calculateAssetPath($string, $name, $return, $filename_path) |
||
420 | |||
421 | /** |
||
422 | * Método que extrae el recurso css de una línea de estilos css |
||
423 | * @param $handle |
||
424 | * @param string $filename_path |
||
425 | * @throws ConfigException |
||
426 | */ |
||
427 | public static function extractCssLineResource($handle, $filename_path) |
||
447 | |||
448 | /** |
||
449 | * Método que extrae el nombre del fichero de un recurso |
||
450 | * @param string $source |
||
451 | * @return string |
||
452 | */ |
||
453 | protected function extractSourceFilename($source) |
||
467 | |||
468 | /** |
||
469 | * @param string $file |
||
470 | */ |
||
471 | protected function loopCssLines($file) |
||
487 | } |
||
488 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.