Passed
Push — master ( bf5903...f5157c )
by Fran
04:43
created

AssetsParser::processCssLine()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8.6298

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 6
nop 3
dl 0
loc 23
ccs 11
cts 14
cp 0.7856
crap 8.6298
rs 6.1403
c 0
b 0
f 0
1
<?php
2
3
namespace PSFS\base\extension;
4
5
use MatthiasMullie\Minify\CSS;
6
use MatthiasMullie\Minify\JS;
7
use PSFS\base\config\Config;
8
use PSFS\base\exception\ConfigException;
9
use PSFS\base\Logger;
10
use PSFS\base\Template;
11
use PSFS\base\types\helpers\GeneratorHelper;
12
13
/**
14
 * Class AssetsParser
15
 * @package PSFS\base\extension
16
 */
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')
34
    {
35 1
        $this->type = $type;
36 1
        $this->path = WEB_DIR . DIRECTORY_SEPARATOR;
37 1
        $this->domains = Template::getDomains(true);
38 1
        $this->debug = Config::getInstance()->getDebugMode();
39 1
    }
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 1
            foreach ($this->domains as $domain => $paths) {
75 1
                $domain_filename = str_replace($domain, $paths["public"], $filename);
76 1
                if (file_exists($domain_filename) && preg_match('/\.' . $this->type . '$/i', $domain_filename)) {
77 1
                    $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)
91
    {
92 1
        $cache = Config::getParam('cache.var', '');
93 1
        $this->hash = $hash . (strlen($cache) ? '.' : '') . $cache;
94 1
        return $this;
95
    }
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()
104
    {
105
        //Unificamos ficheros para que no se retarde mucho el proceso
106 1
        $this->files = array_unique($this->files);
107 1
        switch ($this->type) {
108
            default:
109 1
            case "js":
110 1
                $this->compileJs();
111 1
                break;
112 1
            case "css":
113 1
                $this->compileCss();
114 1
                break;
115
        }
116
117 1
        return $this;
118
    }
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 1
                $minifier = new CSS();
132 1
                foreach ($this->files as $file) {
133 1
                    $data = $this->processCssLine($file, $base, $data);
134
                }
135
            }
136 1
            if($this->debug) {
137
                $this->storeContents($base . $this->hash . ".css", $data);
138
            } else {
139 1
                $minifier = new CSS();
140 1
                $minifier->add($data);
141 1
                ini_set('max_execution_time', -1);
142 1
                ini_set('memory_limit', -1);
143 1
                GeneratorHelper::createDir($base);
144 1
                $minifier->minify($base . $this->hash . ".css");
145 1
                unset($cssMinifier);
146 1
                ini_restore('memory_limit');
147 1
                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 1
                $minifier = new JS();
165 1
                foreach ($this->files as $file) {
166 1
                    $path_parts = explode("/", $file);
167 1
                    if (file_exists($file)) {
168 1
                        if ($this->debug) {
169
                            $data = $this->putDebugJs($path_parts, $base, $file);
170 1
                        } elseif (!file_exists($base . $this->hash . ".js")) {
171 1
                            $minifier->add($file);
172
                            //$data = $this->putProductionJs($base, $file, $data);
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
173
                        }
174
                    }
175
                }
176 1
                if($this->debug) {
177
                    $this->storeContents($base . $this->hash . ".js", $data);
178
                } else {
179 1
                    ini_set('max_execution_time', -1);
180 1
                    ini_set('memory_limit', -1);
181 1
                    GeneratorHelper::createDir($base);
182 1
                    $minifier->minify($base . $this->hash . ".js");
183 1
                    ini_restore('memory_limit');
184 1
                    ini_restore('max_execution_time');
185
                }
186 1
                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 View Code Duplication
    private function storeContents($path, $content = "")
199
    {
200
        GeneratorHelper::createDir(dirname($path));
201
        if ("" !== $content && false === file_put_contents($path, $content)) {
202
            throw new ConfigException(_('No se tienen permisos para escribir en ' . $path));
203
        }
204
    }
205
206
    /**
207
     * Método que imprime el resultado de la generación de los assets
208
     */
209 1
    public function printHtml()
210
    {
211 1
        switch ($this->type) {
212
            default:
213 1
            case "js":
214 1
                $this->printJs();
215 1
                break;
216 1
            case "css":
217 1
                $this->printCss();
218 1
                break;
219
        }
220 1
    }
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()
226
    {
227 1
        if ($this->debug && 0 < count($this->compiled_files)) {
228
            foreach ($this->compiled_files as $file) {
229
                echo "\t\t<script type='text/javascript' src='{$file}'></script>\n";
230
            }
231
        } else {
232 1
            echo "\t\t<script type='text/javascript' src='/js/" . $this->hash . ".js'></script>\n";
233
        }
234 1
    }
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()
240
    {
241 1
        if ($this->debug && 0 < count($this->compiled_files)) {
242
            foreach ($this->compiled_files as $file) {
243
                echo "\t\t<link href='{$file}' rel='stylesheet' media='screen, print'>";
244
            }
245
        } else {
246 1
            echo "\t\t<link href='/css/" . $this->hash . ".css' rel='stylesheet'>";
247
        }
248 1
    }
249
250
    /**
251
     * @param string $source
252
     * @param string $file
253
     */
254 1
    protected function extractCssResources($source, $file)
255
    {
256 1
        $source_file = $this->extractSourceFilename($source);
257 1
        $orig = realpath(dirname($file) . DIRECTORY_SEPARATOR . $source_file);
258 1
        $orig_part = preg_split('/(\/|\\\)public(\/|\\\)/i', $orig);
259
        try {
260 1
            if (count($source) > 1 && array_key_exists(1, $orig_part)) {
261 1
                $dest = $this->path . $orig_part[1];
262 1
                GeneratorHelper::createDir(dirname($dest));
263 1
                if (!file_exists($dest) || filemtime($orig) > filemtime($dest)) {
264 1
                    if (@copy($orig, $dest) === FALSE) {
265
                        throw new \RuntimeException('Can\' copy ' . $dest . '');
266
                    }
267 1
                    Logger::log("$orig copiado a $dest", LOG_INFO);
268
                }
269
            }
270
        } catch (\Exception $e) {
271
            Logger::log($e->getMessage(), LOG_ERR);
272
        }
273 1
    }
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 1
    protected function processCssLine($file, $base, $data)
284
    {
285 1
        if (file_exists($file)) {
286 1
            $path_parts = explode("/", $file);
287 1
            $file_path = $this->hash . "_" . $path_parts[count($path_parts) - 1];
288 1
            if (!file_exists($base . $file_path) || filemtime($base . $file_path) < filemtime($file) || $this->debug) {
289
                //Si tenemos modificaciones tenemos que compilar de nuevo todos los ficheros modificados
290 1
                if (file_exists($base . $this->hash . ".css") && @unlink($base . $this->hash . ".css") === false) {
291
                    throw new ConfigException("Can't unlink file " . $base . $this->hash . ".css");
292
                }
293 1
                $this->loopCssLines($file);
294
            }
295 1
            if ($this->debug) {
296
                $data = file_get_contents($file);
297
                $this->storeContents($base . $file_path, $data);
298
            } else {
299 1
                $data .= file_get_contents($file);
300
            }
301 1
            $this->compiled_files[] = "/css/" . $file_path;
302
        }
303
304 1
        return $data;
305
    }
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)
315
    {
316
        $file_path = $this->hash . "_" . $path_parts[count($path_parts) - 1];
317
        $this->compiled_files[] = "/js/" . $file_path;
318
        $data = "";
319
        if (!file_exists($base . $file_path) || filemtime($base . $file_path) < filemtime($file)) {
320
            $data = file_get_contents($file);
321
            $this->storeContents($base . $file_path, $data);
322
        }
323
        return $data;
324
    }
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
    public static function findDomainPath($string, $file_path)
334
    {
335
        $domains = Template::getDomains(TRUE);
336
        $filename_path = null;
337 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
        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)
360
    {
361
        $ppath = explode("/", $string);
362
        $original_filename = $ppath[count($ppath) - 1];
363
        $base = WEB_DIR . DIRECTORY_SEPARATOR;
364
        $file = "";
365
        $html_base = "";
366
        $debug = Config::getInstance()->getDebugMode();
367
        $cache = Config::getInstance()->get('cache.var');
368
        $cache = $cache ? '.' . $cache : '';
369
        $finfo = finfo_open(FILEINFO_MIME_TYPE); // devuelve el tipo mime de su extensión
370
        $mime = finfo_file($finfo, $filename_path);
371
        finfo_close($finfo);
372
        if (preg_match('/\.css$/i', $string)) {
373
            $file = "/" . substr(md5($string), 0, 8) . "$cache.css";
374
            $html_base = "css";
375
            if ($debug) {
376
                $file = str_replace(".css", "_" . $original_filename, $file);
377
            }
378
        } elseif (preg_match('/\.js$/i', $string)) {
379
            $file = "/" . substr(md5($string), 0, 8) . "$cache.js";
380
            $html_base = "js";
381
            if ($debug) {
382
                $file = str_replace(".js", "_" . $original_filename, $file);
383
            }
384 View Code Duplication
        } elseif (preg_match("/image/i", $mime)) {
385
            $ext = explode(".", $string);
386
            $file = "/" . substr(md5($string), 0, 8) . "." . $ext[count($ext) - 1];
387
            $html_base = "img";
388
            if ($debug) {
389
                $file = str_replace("." . $ext[count($ext) - 1], "_" . $original_filename, $file);
390
            }
391
        } elseif (preg_match("/(doc|pdf)/i", $mime)) {
392
            $ext = explode(".", $string);
393
            $file = "/" . substr(md5($string), 0, 8) . "." . $ext[count($ext) - 1];
394
            $html_base = "docs";
395
            if ($debug) {
396
                $file = str_replace("." . $ext[count($ext) - 1], "_" . $original_filename, $file);
397
            }
398 View Code Duplication
        } elseif (preg_match("/(video|audio|ogg)/i", $mime)) {
399
            $ext = explode(".", $string);
400
            $file = "/" . substr(md5($string), 0, 8) . "." . $ext[count($ext) - 1];
401
            $html_base = "media";
402
            if ($debug) {
403
                $file = str_replace("." . $ext[count($ext) - 1], "_" . $original_filename, $file);
404
            }
405
        } elseif (preg_match("/(text|html)/i", $mime)) {
406
            $ext = explode(".", $string);
407
            $file = "/" . substr(md5($string), 0, 8) . "." . $ext[count($ext) - 1];
408
            $html_base = "templates";
409
            if ($debug) {
410
                $file = str_replace("." . $ext[count($ext) - 1], "_" . $original_filename, $file);
411
            }
412
        } elseif (!$return && !is_null($name)) {
413
            $html_base = '';
414
            $file = $name;
415
        }
416
        $file_path = $html_base . $file;
417
418
        return array($base, $html_base, $file_path);
419
    }
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)
428
    {
429
        $line = fgets($handle);
430
        $urls = array();
431
        if (preg_match_all('#url\((.*?)\)#', $line, $urls, PREG_SET_ORDER)) {
432
            foreach ($urls as $source) {
433
                $orig = self::calculateResourcePathname($filename_path, $source);
434
                $orig_part = preg_split("/Public/i", $orig);
435
                $dest = WEB_DIR . $orig_part[1];
436
                GeneratorHelper::createDir(dirname($dest));
437
                if (@copy($orig, $dest) === false) {
438
                    throw new ConfigException("Can't copy " . $orig . " to " . $dest);
439
                }
440
            }
441
        }
442
    }
443
444
    /**
445
     * Método que extrae el nombre del fichero de un recurso
446
     * @param string $source
447
     * @return string
448
     */
449 1
    protected function extractSourceFilename($source)
450
    {
451 1
        $source_file = preg_replace("/'/", "", $source[1]);
452 1 View Code Duplication
        if (preg_match('/\#/', $source_file)) {
453 1
            $source_file = explode("#", $source_file);
454 1
            $source_file = $source_file[0];
455
        }
456 1 View Code Duplication
        if (preg_match('/\?/', $source_file)) {
457 1
            $source_file = explode("?", $source_file);
458 1
            $source_file = $source_file[0];
459 1
            return $source_file;
460
        }
461 1
        return $source_file;
462
    }
463
464
    /**
465
     * @param string $file
466
     */
467 1
    protected function loopCssLines($file)
468
    {
469 1
        $handle = @fopen($file, 'r');
470 1
        if ($handle) {
471 1
            while (!feof($handle)) {
472 1
                $line = fgets($handle);
473 1
                $urls = array();
474 1
                if (preg_match_all('#url\((.*?)\)#', $line, $urls, PREG_SET_ORDER)) {
475 1
                    foreach ($urls as $source) {
476 1
                        $this->extractCssResources($source, $file);
477
                    }
478
                }
479
            }
480 1
            fclose($handle);
481
        }
482 1
    }
483
}
484