Test Failed
Push — master ( cc821f...fdc4d2 )
by Fran
09:36 queued 04:02
created

AssetsParser::findDomainPath()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 9
Ratio 56.25 %

Code Coverage

Tests 5
CRAP Score 8.125

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 2
nop 2
dl 9
loc 16
ccs 5
cts 10
cp 0.5
crap 8.125
rs 8.8571
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
            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)
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
                $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);
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
                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()
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
    protected function extractCssResources($source, $file)
255
    {
256
        $source_file = $this->extractSourceFilename($source);
257
        $orig = realpath(dirname($file) . DIRECTORY_SEPARATOR . $source_file);
258
        $orig_part = preg_split('/(\/|\\\)public(\/|\\\)/i', $orig);
259
        try {
260
            if (count($source) > 1 && array_key_exists(1, $orig_part)) {
261
                $dest = $this->path . $orig_part[1];
262
                GeneratorHelper::createDir(dirname($dest));
263
                if (!file_exists($dest) || filemtime($orig) > filemtime($dest)) {
264
                    if (@copy($orig, $dest) === FALSE) {
265
                        throw new \RuntimeException('Can\' copy ' . $dest . '');
266
                    }
267
                    Logger::log("$orig copiado a $dest", LOG_INFO);
268
                }
269
            }
270
        } catch (\Exception $e) {
271
            Logger::log($e->getMessage(), LOG_ERR);
272
        }
273
    }
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)
284
    {
285
        if (file_exists($file)) {
286
            $path_parts = explode("/", $file);
287
            $file_path = $this->hash . "_" . $path_parts[count($path_parts) - 1];
288
            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
                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
                $this->loopCssLines($file);
294
            }
295
            if ($this->debug) {
296
                $data = file_get_contents($file);
297
                $this->storeContents($base . $file_path, $data);
298
            } else {
299
                $data .= file_get_contents($file);
300
            }
301
            $this->compiled_files[] = "/css/" . $file_path;
302
        }
303
304
        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 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)
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
                if(!empty($orig)) {
435
                    $orig_part = preg_split("/Public/i", $orig);
436
                    $dest = WEB_DIR . $orig_part[1];
437
                    GeneratorHelper::createDir(dirname($dest));
438
                    if (@copy($orig, $dest) === false) {
439
                        throw new ConfigException("Can't copy " . $orig . " to " . $dest);
440
                    }
441
                } else {
442
                    Logger::log($filename_path . ' has an empty origin with the url ' . $source, LOG_WARNING);
443
                }
444
            }
445
        }
446
    }
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)
454
    {
455
        $source_file = preg_replace("/'/", "", $source[1]);
456 View Code Duplication
        if (preg_match('/\#/', $source_file)) {
457
            $source_file = explode("#", $source_file);
458
            $source_file = $source_file[0];
459
        }
460 View Code Duplication
        if (preg_match('/\?/', $source_file)) {
461
            $source_file = explode("?", $source_file);
462
            $source_file = $source_file[0];
463
            return $source_file;
464
        }
465
        return $source_file;
466
    }
467
468
    /**
469
     * @param string $file
470
     */
471
    protected function loopCssLines($file)
472
    {
473
        $handle = @fopen($file, 'r');
474
        if ($handle) {
475
            while (!feof($handle)) {
476
                $line = fgets($handle);
477
                $urls = array();
478
                if (preg_match_all('#url\((.*?)\)#', $line, $urls, PREG_SET_ORDER)) {
479
                    foreach ($urls as $source) {
480
                        $this->extractCssResources($source, $file);
481
                    }
482
                }
483
            }
484
            fclose($handle);
485
        }
486
    }
487
}
488