Completed
Push — master ( 7346cf...68e36d )
by Ryan
18:45 queued 13:05
created

Asset::lastModifiedAt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php namespace Anomaly\Streams\Platform\Asset;
2
3
use Anomaly\Streams\Platform\Addon\Theme\ThemeCollection;
4
use Anomaly\Streams\Platform\Application\Application;
5
use Anomaly\Streams\Platform\Asset\Filter\CoffeeFilter;
6
use Anomaly\Streams\Platform\Asset\Filter\CssMinFilter;
7
use Anomaly\Streams\Platform\Asset\Filter\JsMinFilter;
8
use Anomaly\Streams\Platform\Asset\Filter\LessFilter;
9
use Anomaly\Streams\Platform\Asset\Filter\NodeLessFilter;
10
use Anomaly\Streams\Platform\Asset\Filter\ParseFilter;
11
use Anomaly\Streams\Platform\Asset\Filter\RubySassFilter;
12
use Anomaly\Streams\Platform\Asset\Filter\RubyScssFilter;
13
use Anomaly\Streams\Platform\Asset\Filter\SassFilter;
14
use Anomaly\Streams\Platform\Asset\Filter\ScssFilter;
15
use Anomaly\Streams\Platform\Asset\Filter\SeparatorFilter;
16
use Anomaly\Streams\Platform\Asset\Filter\StylusFilter;
17
use Anomaly\Streams\Platform\Routing\UrlGenerator;
18
use Assetic\Asset\AssetCollection;
19
use Assetic\Asset\FileAsset;
20
use Assetic\Asset\GlobAsset;
21
use Assetic\Filter\PhpCssEmbedFilter;
22
use Collective\Html\HtmlBuilder;
23
use Illuminate\Contracts\Config\Repository;
24
use Illuminate\Filesystem\Filesystem;
25
use Illuminate\Http\Request;
26
use League\Flysystem\MountManager;
27
28
/**
29
 * Class Asset
30
 *
31
 * @link   http://pyrocms.com/
32
 * @author PyroCMS, Inc. <[email protected]>
33
 * @author Ryan Thompson <[email protected]>
34
 */
35
class Asset
36
{
37
38
    /**
39
     * The public base directory.
40
     *
41
     * @var null
42
     */
43
    protected $directory = null;
44
45
    /**
46
     * Groups of assets. Groups can
47
     * be single files as well.
48
     *
49
     * @var array
50
     */
51
    protected $collections = [];
52
53
    /**
54
     * The URL generator.
55
     *
56
     * @var UrlGenerator
57
     */
58
    protected $url;
59
60
    /**
61
     * The HTML utility.
62
     *
63
     * @var HtmlBuilder
64
     */
65
    protected $html;
66
67
    /**
68
     * The files system.
69
     *
70
     * @var Filesystem
71
     */
72
    protected $files;
73
74
    /**
75
     * Asset path hints by namespace.
76
     *
77
     * 'module.users' => 'the/resources/path'
78
     *
79
     * @var AssetPaths
80
     */
81
    protected $paths;
82
83
    /**
84
     * The asset parser utility.
85
     *
86
     * @var AssetParser
87
     */
88
    protected $parser;
89
90
    /**
91
     * The theme collection.
92
     *
93
     * @var ThemeCollection
94
     */
95
    protected $themes;
96
97
    /**
98
     * The mount manager.
99
     *
100
     * @var MountManager
101
     */
102
    protected $manager;
103
104
    /**
105
     * The HTTP request.
106
     *
107
     * @var Request
108
     */
109
    protected $request;
110
111
    /**
112
     * The stream application.
113
     *
114
     * @var Application
115
     */
116
    protected $application;
117
118
    /**
119
     * The config repository.
120
     *
121
     * @var Repository
122
     */
123
    protected $config;
124
125
    /**
126
     * Create a new Application instance.
127
     *
128
     * @param Application     $application
129
     * @param ThemeCollection $themes
130
     * @param MountManager    $manager
131
     * @param AssetParser     $parser
132
     * @param Repository      $config
133
     * @param Filesystem      $files
134
     * @param AssetPaths      $paths
135
     * @param Request         $request
136
     * @param HtmlBuilder     $html
137
     * @param UrlGenerator    $url
138
     */
139 View Code Duplication
    public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
140
        Application $application,
141
        ThemeCollection $themes,
142
        MountManager $manager,
143
        AssetParser $parser,
144
        Repository $config,
145
        Filesystem $files,
146
        AssetPaths $paths,
147
        Request $request,
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
148
        HtmlBuilder $html,
149
        UrlGenerator $url
150
    ) {
151
        $this->url         = $url;
152
        $this->html        = $html;
153
        $this->files       = $files;
154
        $this->paths       = $paths;
155
        $this->config      = $config;
156
        $this->themes      = $themes;
157
        $this->parser      = $parser;
158
        $this->manager     = $manager;
159
        $this->request     = $request;
160
        $this->application = $application;
161
    }
162
163
    /**
164
     * Add an asset or glob pattern to an asset collection.
165
     *
166
     * This should support the asset being the collection
167
     * and the asset (for single files) internally
168
     * so asset.links / asset.scripts will work.
169
     *
170
     * @param             $collection
171
     * @param             $file
172
     * @param  array      $filters
173
     * @return $this
174
     * @throws \Exception
175
     */
176
    public function add($collection, $file, array $filters = [])
177
    {
178
        if (!isset($this->collections[$collection])) {
179
            $this->collections[$collection] = [];
180
        }
181
182
        $filters = $this->addConvenientFilters($file, $filters);
183
184
        $file = $this->paths->realPath($file);
185
186
        /*
187
         * If this is a remote or single existing
188
         * file then add it normally.
189
         */
190
        if (starts_with($file, ['http', '//']) || file_exists($file)) {
191
            $this->collections[$collection][$file] = $filters;
192
193
            return $this;
194
        }
195
196
        /*
197
         * If this is a valid glob pattern then add
198
         * it to the collection and add the glob filter.
199
         */
200
        if (count(glob($file)) > 0) {
201
            $this->collections[$collection][$file] = array_merge($filters, ['glob']);
202
203
            return $this;
204
        }
205
206
        if ($this->config->get('app.debug')) {
207
            throw new \Exception("Asset [{$file}] does not exist!");
208
        }
209
    }
210
211
    /**
212
     * Download a file and return it's path.
213
     *
214
     * @param              $url
215
     * @param  int         $ttl
216
     * @param  null        $path
217
     * @return null|string
218
     */
219
    public function download($url, $ttl = 3600, $path = null)
220
    {
221
        $path = $this->paths->downloadPath($url, $path);
222
223
        if (!$this->files->isDirectory($directory = dirname($path = public_path(ltrim($path, '/\\'))))) {
224
            $this->files->makeDirectory($directory, 0777, true);
225
        }
226
227
        if (!$this->files->exists($path) || filemtime($path) < (time() - $ttl)) {
228
            $this->files->put($path, file_get_contents($url));
229
        }
230
231
        return $path;
232
    }
233
234
    /**
235
     * Return the contents of a collection.
236
     *
237
     * @param         $collection
238
     * @param  array  $filters
239
     * @return string
240
     */
241
    public function inline($collection, array $filters = [])
242
    {
243
        return file_get_contents(
244
            $this->paths->realPath('public::' . ltrim($this->path($collection, $filters), '/\\'))
245
        );
246
    }
247
248
    /**
249
     * Return the URL to a compiled asset collection.
250
     *
251
     * @param         $collection
252
     * @param  array  $filters
253
     * @return string
254
     */
255
    public function url($collection, array $filters = [], array $parameters = [], $secure = null)
256
    {
257
        if (!isset($this->collections[$collection])) {
258
            $this->add($collection, $collection, $filters);
259
        }
260
261
        if (!$path = $this->getPath($collection, $filters)) {
262
            return null;
263
        }
264
265
        return $this->url->asset($this->getPath($collection, $filters), $parameters, $secure);
266
    }
267
268
    /**
269
     * Return the path to a compiled asset collection.
270
     *
271
     * @param         $collection
272
     * @param  array  $filters
273
     * @return string
274
     */
275
    public function path($collection, array $filters = [])
276
    {
277
        if (!isset($this->collections[$collection])) {
278
            $this->add($collection, $collection, $filters);
279
        }
280
281
        return $this->request->getBasePath() . $this->getPath($collection, $filters);
282
    }
283
284
    /**
285
     * Return the asset path to a compiled asset collection.
286
     *
287
     * @param         $collection
288
     * @param  array  $filters
289
     * @return string
290
     */
291
    public function asset($collection, array $filters = [])
292
    {
293
        if (!isset($this->collections[$collection])) {
294
            $this->add($collection, $collection, $filters);
295
        }
296
297
        return $this->path($collection, $filters);
298
    }
299
300
    /**
301
     * Return the script tag for a collection.
302
     *
303
     * @param         $collection
304
     * @param  array  $filters
305
     * @param  array  $attributes
306
     * @return string
307
     */
308
    public function script($collection, array $filters = [], array $attributes = [])
309
    {
310
        $attributes['src'] = $this->path($collection, $filters);
311
312
        return '<script' . $this->html->attributes($attributes) . '></script>';
313
    }
314
315
    /**
316
     * Return the style tag for a collection.
317
     *
318
     * @param         $collection
319
     * @param  array  $filters
320
     * @param  array  $attributes
321
     * @return string
322
     */
323 View Code Duplication
    public function style($collection, array $filters = [], array $attributes = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
324
    {
325
        $defaults = ['media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet'];
326
327
        $attributes = $attributes + $defaults;
328
329
        $attributes['href'] = $this->asset($collection, $filters);
330
331
        return '<link' . $this->html->attributes($attributes) . '>';
332
    }
333
334
    /**
335
     * Return an array of script tags.
336
     *
337
     * @param        $collection
338
     * @param  array $filters
339
     * @param  array $attributes
340
     * @return array
341
     */
342
    public function scripts($collection, array $filters = [], array $attributes = [])
343
    {
344
        return array_map(
345
            function ($path) use ($attributes) {
346
                $attributes['src'] = $path;
347
348
                return '<script' . $this->html->attributes($attributes) . '></script>';
349
            },
350
            $this->paths($collection, $filters)
351
        );
352
    }
353
354
    /**
355
     * Return an array of style tags.
356
     *
357
     * @param        $collection
358
     * @param  array $filters
359
     * @param  array $attributes
360
     * @return array
361
     */
362 View Code Duplication
    public function styles($collection, array $filters = [], array $attributes = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
363
    {
364
        return array_map(
365
            function ($path) use ($attributes) {
366
                $defaults = ['media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet'];
367
368
                $attributes = $attributes + $defaults;
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $attributes, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
369
370
                $attributes['href'] = $path;
371
372
                return '<link' . $this->html->attributes($attributes) . '>';
373
            },
374
            $this->paths($collection, $filters)
375
        );
376
    }
377
378
    /**
379
     * Return an array of paths to an asset collection.
380
     *
381
     * This instead of combining the collection contents
382
     * just returns an array of individual processed
383
     * paths instead.
384
     *
385
     * @param        $collection
386
     * @param  array $additionalFilters
387
     * @return array
388
     */
389
    public function paths($collection, array $additionalFilters = [])
390
    {
391
        if (!isset($this->collections[$collection])) {
392
            return [];
393
        }
394
395
        return array_filter(
396
            array_map(
397
                function ($file, $filters) use ($additionalFilters) {
398
                    $filters = array_filter(array_unique(array_merge($filters, $additionalFilters)));
399
400
                    return $this->asset($file, $filters);
401
                },
402
                array_keys($this->collections[$collection]),
403
                array_values($this->collections[$collection])
404
            )
405
        );
406
    }
407
408
    /**
409
     * Return an array of style URLs.
410
     *
411
     * @param        $collection
412
     * @param  array $filters
413
     * @param  array $attributes
414
     * @param null   $secure
415
     * @return array
416
     */
417
    public function urls($collection, array $filters = [], array $attributes = [], $secure = null)
418
    {
419
        return array_map(
420
            function ($path) use ($attributes, $secure) {
421
                return $this->url($path, [], $attributes, $secure);
422
            },
423
            $this->paths($collection, $filters)
424
        );
425
    }
426
427
    /**
428
     * @param $collection
429
     * @param $filters
430
     * @return string
431
     */
432
    protected function getPath($collection, $filters)
433
    {
434
        /*
435
         * If the asset is remote just return it.
436
         */
437
        if (starts_with($collection, ['http', '//'])) {
438
            return $collection;
439
        }
440
441
        $path = $this->paths->outputPath($collection);
442
443
        if ($this->shouldPublish($path, $collection, $filters)) {
444
            $this->publish($path, $collection, $filters);
445
        }
446
447
        if (
448
            !in_array('noversion', $filters) &&
449
            ($this->config->get('streams::assets.version') || in_array('version', $filters))
450
        ) {
451
            $path .= '?v=' . filemtime(public_path(trim($path, '/\\')));
452
        }
453
454
        return $path;
455
    }
456
457
    /**
458
     * Return the collection path. This
459
     * is primarily used to determine paths
460
     * to single assets.
461
     *
462
     * @param $collection
463
     * @return string
464
     */
465
    public function getCollectionPath($collection)
466
    {
467
        return ($this->request->segment(1) == 'admin' ? 'admin' : 'public') . '/' . ltrim(
468
                str_replace(base_path(), '', $this->paths->realPath($collection)),
469
                '/\\'
470
            );
471
    }
472
473
    /**
474
     * Publish the collection of assets to the path.
475
     *
476
     * @param $path
477
     * @param $collection
478
     * @param $additionalFilters
479
     */
480
    protected function publish($path, $collection, $additionalFilters)
481
    {
482
        $path = ltrim($path, '/\\');
483
484
        if (str_contains($collection, public_path())) {
485
            return;
486
        }
487
488
        $assets = $this->getAssetCollection($collection, $additionalFilters);
489
490
        $path = $this->directory . DIRECTORY_SEPARATOR . $path;
491
492
        $this->files->makeDirectory((new \SplFileInfo($path))->getPath(), 0777, true, true);
493
494
        $this->files->put($path, $assets->dump());
495
496
        if ($this->paths->extension($path) == 'css') {
497
            try {
498
                $this->files->put(
499
                    $path,
500
                    app('twig')->render(
501
                        str_replace($this->application->getAssetsPath(DIRECTORY_SEPARATOR), 'assets::', $path)
502
                    )
503
                );
504
            } catch (\Exception $e) {
505
                // Don't even..
506
            }
507
        }
508
    }
509
510
    /**
511
     * Transform an array of filters to
512
     * an array of Assetic filters.
513
     *
514
     * @param  $filters
515
     * @param  $hint
516
     * @return mixed
517
     */
518
    protected function transformFilters($filters, $hint)
519
    {
520
        foreach ($filters as $k => &$filter) {
521
522
            /*
523
             * Parse Twg tags in the asset content.
524
             */
525
            if ($filter == 'parse') {
526
                $filter = new ParseFilter($this->parser);
527
528
                continue;
529
            }
530
531
            /*
532
             * Compile LESS to CSS with PHP.
533
             */
534 View Code Duplication
            if ($filter == 'less' && $this->config->get('streams::assets.filters.less', 'php') == 'php') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
535
                $filter = new LessFilter($this->parser);
536
537
                continue;
538
            }
539
540
            /*
541
             * Compile LESS to CSS with Node.
542
             */
543 View Code Duplication
            if ($filter == 'less' && $this->config->get('streams::assets.filters.less', 'php') == 'node') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
544
                $filter = new NodeLessFilter($this->parser);
545
546
                continue;
547
            }
548
549
            /*
550
             * Compile Stylus to CSS.
551
             */
552
            if ($filter == 'styl') {
553
                $filter = new StylusFilter($this->parser);
554
555
                continue;
556
            }
557
558
            /*
559
             * Compile SCSS to CSS with PHP.
560
             */
561 View Code Duplication
            if ($filter == 'scss' && $this->config->get('streams::assets.filters.sass', 'php') == 'php') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
562
                $filter = new ScssFilter($this->parser);
563
564
                continue;
565
            }
566
567
            /*
568
             * Compile SCSS to CSS with Ruby.
569
             */
570 View Code Duplication
            if ($filter == 'scss' && $this->config->get('streams::assets.filters.sass', 'php') == 'ruby') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
571
                $filter = new RubyScssFilter($this->parser);
572
573
                continue;
574
            }
575
576
            /*
577
             * Compile SASS to CSS with PHP.
578
             */
579 View Code Duplication
            if ($filter == 'sass' && $this->config->get('streams::assets.filters.sass', 'php') == 'php') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
580
                $filter = new SassFilter($this->parser);
581
582
                continue;
583
            }
584
585
            /*
586
             * Compile SASS to CSS with Ruby.
587
             */
588 View Code Duplication
            if ($filter == 'sass' && $this->config->get('streams::assets.filters.sass', 'php') == 'ruby') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
589
                $filter = new RubySassFilter($this->parser);
590
591
                continue;
592
            }
593
594
            /*
595
             * Compile CoffeeScript to JS
596
             */
597
            if ($filter == 'coffee') {
598
                $filter = new CoffeeFilter($this->parser);
599
600
                continue;
601
            }
602
603
            /*
604
             * Look for and embed CSS images.
605
             */
606
            if ($filter == 'embed') {
607
                $filter = new PhpCssEmbedFilter();
608
609
                continue;
610
            }
611
612
            /*
613
             * Minify JS
614
             */
615
            if ($filter == 'min' && $hint == 'js') {
616
                $filter = new JsMinFilter();
617
618
                continue;
619
            }
620
621
            /*
622
             * Minify CSS
623
             */
624
            if ($filter == 'min' && $hint == 'css') {
625
                $filter = new CssMinFilter();
626
627
                continue;
628
            }
629
630
            /*
631
             * Glob is a flag that's used later.
632
             */
633
            if ($filter == 'glob') {
634
                continue;
635
            }
636
637
            /*
638
             * No filter class could be determined!
639
             */
640
            $filter = null;
641
        }
642
643
        /*
644
         * Be sure to separate JS concatenations.
645
         */
646
        if ($hint == 'js') {
647
            $filters[] = new SeparatorFilter();
648
        }
649
650
        return array_filter($filters);
651
    }
652
653
    /**
654
     * Add filters that we can assume based
655
     * on the asset's file name.
656
     *
657
     * @param  $file
658
     * @param  $filters
659
     * @return array
660
     */
661
    protected function addConvenientFilters($file, $filters)
662
    {
663
        if (ends_with($file, '.less')) {
664
            $filters[] = 'less';
665
        }
666
667
        if (ends_with($file, '.styl')) {
668
            $filters[] = 'styl';
669
        }
670
671
        if (ends_with($file, '.scss')) {
672
            $filters[] = 'scss';
673
        }
674
675
        if (ends_with($file, '.coffee')) {
676
            $filters[] = 'coffee';
677
        }
678
679
        return array_unique($filters);
680
    }
681
682
    /**
683
     * Decide whether we need to publish the file
684
     * to the path or not.
685
     *
686
     * @param        $path
687
     * @param        $collection
688
     * @param  array $filters
689
     * @return bool
690
     */
691
    protected function shouldPublish($path, $collection, array $filters = [])
692
    {
693
        $path = ltrim($path, '/\\');
694
695
        if (starts_with($path, 'http')) {
696
            return false;
697
        }
698
699
        if (!$this->files->exists($path)) {
700
            return true;
701
        }
702
703
        if (in_array('force', $this->collectionFilters($collection, $filters))) {
704
            return true;
705
        }
706
707
        $debug = $this->config->get('streams::assets.live', false);
708
709
        $live = in_array('live', $this->collectionFilters($collection, $filters));
710
711
        if ($debug === true && $live) {
712
            return true;
713
        }
714
715 View Code Duplication
        if ($debug == 'public' && $live && $this->request->segment(1) !== 'admin') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
716
            return true;
717
        }
718
719 View Code Duplication
        if ($debug == 'admin' && $live && $this->request->segment(1) === 'admin') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
720
            return true;
721
        }
722
723
        if ($this->request->isNoCache() && $this->lastModifiedAt('theme::') > filemtime($path)) {
724
            return true;
725
        }
726
727
        // Merge filters from collection files.
728
        foreach ($this->collections[$collection] as $fileFilters) {
729
            $filters = array_filter(array_unique(array_merge($filters, $fileFilters)));
730
        }
731
732
        $assets = $this->getAssetCollection($collection);
733
734
        // If any of the files are more recent than the cache file, publish, otherwise skip
735
        if ($assets->getLastModified() < filemtime($path)) {
736
            return false;
737
        }
738
739
        return true;
740
    }
741
742
    /**
743
     * Get the last modified time.
744
     *
745
     * @return integer
746
     */
747
    public function lastModifiedAt($path)
748
    {
749
        $files = glob($this->paths->realPath($path) . '/*');
750
        $files = array_combine($files, array_map("filemtime", $files));
751
752
        arsort($files);
753
754
        return array_shift($files);
755
    }
756
757
    /**
758
     * Add a namespace path hint.
759
     *
760
     * @param  $namespace
761
     * @param  $path
762
     * @return $this
763
     */
764
    public function addPath($namespace, $path)
765
    {
766
        $this->paths->addPath($namespace, $path);
767
768
        return $this;
769
    }
770
771
    /**
772
     * Set the public base directory.
773
     *
774
     * @param  $directory
775
     * @return $this
776
     */
777
    public function setDirectory($directory)
778
    {
779
        $this->directory = $directory;
780
781
        return $this;
782
    }
783
784
    /**
785
     * Create asset collection from collection array
786
     *
787
     * @param                  $collection
788
     * @param  array           $additionalFilters
789
     * @return AssetCollection
790
     */
791
    private function getAssetCollection($collection, $additionalFilters = [])
792
    {
793
        $assets = new AssetCollection();
794
795
        $hint = $this->paths->hint($collection);
796
797
        foreach ($this->collections[$collection] as $file => $filters) {
798
            $filters = array_filter(array_unique(array_merge($filters, $additionalFilters)));
799
800
            $filters = $this->transformFilters($filters, $hint);
801
802
            if (in_array('glob', $filters)) {
803
                unset($filters[array_search('glob', $filters)]);
804
805
                $file = new GlobAsset($file, $filters);
806
            } else {
807
                $file = new FileAsset($file, $filters);
808
            }
809
810
            $assets->add($file);
811
        }
812
813
        return $assets;
814
    }
815
816
    /**
817
     * Return the filters used in a collection.
818
     *
819
     * @param        $collection
820
     * @param  array $filters
821
     * @return array
822
     */
823
    protected function collectionFilters($collection, array $filters = [])
824
    {
825
        return array_unique(
826
            array_merge($filters, call_user_func_array('array_merge', array_get($this->collections, $collection, [])))
827
        );
828
    }
829
830
    /**
831
     * Return nothing.
832
     *
833
     * @return string
834
     */
835
    public function __toString()
836
    {
837
        return '';
838
    }
839
}
840