TemplateAssetsResolver::setAssetsPaths()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Columnis\Model;
4
5
use AssetManager\Resolver\CollectionResolver;
6
use AssetManager\Resolver\MimeResolverAwareInterface;
7
use AssetManager\Service\MimeResolver;
8
use Assetic\Asset\FileAsset;
9
use Assetic\Asset\AssetCollection;
10
use Columnis\Utils\Directory as DirectoryUtils;
11
use SplFileInfo;
12
13
/**
14
 * This resolver allows the resolving of collections.
15
 * Collections are strictly checked by mime-type,
16
 * and added to an AssetCollection when all checks passed.
17
 */
18
class TemplateAssetsResolver extends CollectionResolver implements MimeResolverAwareInterface
19
{
20
21
    /**
22
     * The assets paths
23
     *
24
     * @var array
25
     */
26
    protected $assetsPaths = array();
27
28
    /**
29
     * The mime resolver.
30
     *
31
     * @var MimeResolver
32
     */
33
    protected $mimeResolver;
34
35
    /**
36
     * The templates paths
37
     *
38
     * @var array
39
     */
40
    protected $templatesPathStack = array();
41
42
    /**
43
     * The name of the folder inside the assets paths that will generate the global.css and global.js
44
     *
45
     * @var string
46
     */
47
    protected $globalFolderName;
48
49
    /*
50
     * Regex Pattern to match (first group) the template name
51
     *
52
     * @var string
53
     */
54
    protected $patternTemplateName;
55
56
    /*
57
     * Regex Pattern to match (in any group) if a filename is inside a global assets folder
58
     *
59
     * @var string
60
     */
61
    protected $patternGlobalAssets;
62
63
    /**
64
     * Path to the public dir
65
     *
66
     * @var string
67
     */
68
    protected $publicPath;
69
70
    /**
71
     * Get the Paths where assets are allowed
72
     *
73
     * @return array
74
     */
75 5
    public function getAssetsPaths()
76
    {
77 5
        return $this->assetsPaths;
78
    }
79
80
    /**
81
     * Set the Paths where assets are allowed
82
     *
83
     * @param array $assetsPaths
84
     */
85 13
    public function setAssetsPaths(Array $assetsPaths = null)
86
    {
87 13
        $this->assetsPaths = $assetsPaths;
0 ignored issues
show
Documentation Bug introduced by
It seems like $assetsPaths can be null. However, the property $assetsPaths is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
88 13
    }
89
90
    /**
91
     * Set the mime resolver
92
     *
93
     * @param MimeResolver $resolver
94
     */
95 4
    public function setMimeResolver(MimeResolver $resolver)
96
    {
97 4
        $this->mimeResolver = $resolver;
98 4
    }
99
100
    /**
101
     * Get the mime resolver
102
     *
103
     * @return MimeResolver
104
     */
105 3
    public function getMimeResolver()
106
    {
107 3
        return $this->mimeResolver;
108
    }
109
110
    /**
111
     * Retrieve paths to templates
112
     *
113
     * @return array
114
     */
115 6
    public function getTemplatesPathStack()
116
    {
117 6
        return $this->templatesPathStack;
118
    }
119
120
    /**
121
     * Set the templates paths
122
     *
123
     * @param array $templatesPathStack
124
     */
125 13
    public function setTemplatesPathStack(Array $templatesPathStack)
126
    {
127 13
        $this->templatesPathStack = $templatesPathStack;
128 13
    }
129
130
    /**
131
     * Get the name of the global folder
132
     *
133
     * @return string
134
     */
135 1
    public function getGlobalFolderName()
136
    {
137 1
        return $this->globalFolderName;
138
    }
139
140
    /**
141
     * Set the name of the global folder
142
     *
143
     * @param string $globalFolderName
144
     */
145 13
    public function setGlobalFolderName($globalFolderName = '')
146
    {
147 13
        $this->globalFolderName = $globalFolderName;
148 13
    }
149
150
    /**
151
     * Get the pattern to match the template name
152
     *
153
     * @return string
154
     */
155 7
    public function getPatternTemplateName()
156
    {
157 7
        return $this->patternTemplateName;
158
    }
159
160
    /**
161
     * Get the pattern to match if a file is a global asset
162
     *
163
     * @return string
164
     */
165 2
    public function getPatternGlobalAssets()
166
    {
167 2
        return $this->patternGlobalAssets;
168
    }
169
170
    /**
171
     * Set the pattern to match the template name
172
     *
173
     * @param string $patternTemplateName
174
     */
175 13
    public function setPatternTemplateName($patternTemplateName)
176
    {
177 13
        $this->patternTemplateName = $patternTemplateName;
178 13
    }
179
180
    /**
181
     * Set the pattern to match if a file is a global asset
182
     *
183
     * @param string $patternGlobalAssets
184
     */
185 13
    public function setPatternGlobalAssets($patternGlobalAssets)
186
    {
187 13
        $this->patternGlobalAssets = $patternGlobalAssets;
188 13
    }
189
190
    /**
191
     * Returns the public path
192
     *
193
     * @return string
194
     */
195 1
    public function getPublicPath()
196
    {
197 1
        return $this->publicPath;
198
    }
199
200
    /**
201
     * Sets the public path
202
     *
203
     * @param string $publicPath
204
     */
205
    public function setPublicPath($publicPath)
206
    {
207
        $this->publicPath = $publicPath;
208
    }
209
210
211
    /**
212
     * Constructor
213
     *
214
     * Instantiate, set the assets paths, templates paths and the current template
215
     * @param array $assetsPaths
216
     * @param array $templatesPathStack
217
     */
218 13
    public function __construct(Array $assetsPaths, Array $templatesPathStack)
219
    {
220 13
        parent::__construct();
221 13
        $this->setAssetsPaths($assetsPaths);
222 13
        $this->setTemplatesPathStack($templatesPathStack);
223 13
    }
224
225
    /**
226
     *  Adds a collection of assets with an alias
227
     *
228
     * @param string $alias
229
     * @param array $assets
230
     */
231 4
    public function addToCollections($alias, Array $assets)
232
    {
233 4
        $collections = $this->getCollections();
234 4
        $collections[$alias] = $assets;
235 4
        $this->setCollections($collections);
236 4
    }
237
238
    /**
239
     * Returns the template name if the requested asset belongs to a template
240
     *
241
     * @param string $alias
242
     * @return boolean|array
243
     */
244 7
    public function matchTemplateName($alias)
245
    {
246 7
        $pattern = $this->getPatternTemplateName();
247 7
        $matches = array();
248 7
        if (preg_match($pattern, $alias, $matches)) {
249 4
            return $matches[1];
250
        }
251 4
        return false;
252
    }
253
254
    /**
255
     * Returns true if the asset belongs to a template
256
     *
257
     * @param string $alias
258
     * @return boolean
259
     */
260 4
    public function isTemplateAsset($alias)
261
    {
262 4
        $template = $this->matchTemplateName($alias);
263 4
        if (!$template) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $template of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
264 2
            return false;
265
        }
266 2
        return ($this->getExistantTemplatePath($template) !== null);
267
    }
268
269
    /**
270
     * Returns true if the asset is used globally
271
     *
272
     * @param string $name
273
     * @return boolean
274
     */
275 2
    public function isGlobalAsset($name)
276
    {
277 2
        $pattern = $this->getPatternGlobalAssets();
278 2
        return (preg_match($pattern, $name) > 0);
279
    }
280
281
    /**
282
     * Generates the collection of global assets by iterating over the assets
283
     * in the global assets directory and adds it to the Resolver
284
     *
285
     * @param string $alias
286
     */
287 1
    public function loadGlobalCollection($alias)
288
    {
289 1
        $paths = $this->getGlobalAssetsPaths();
290
291 1
        $extension = pathinfo($alias, PATHINFO_EXTENSION);
292 1
        $files = $this->generateCollection($paths, $extension);
293 1
        $this->addToCollections($alias, $files);
294 1
    }
295
296
    /**
297
     * Generates the collection of the template assets by iterating over the assets
298
     * in the template directory and adds it to the Resolver
299
     *
300
     * @param string $alias
301
     */
302 3
    public function loadTemplateCollection($alias)
303
    {
304 3
        $templateName = $this->matchTemplateName($alias);
305 3
        if ($templateName !== false) {
306 2
            $path = $this->getExistantTemplatePath($templateName);
307 2
            if ($path !== null) {
308 2
                $template = new Template();
309 2
                $template->setName($templateName);
310 2
                $template->setPath($path);
311
312 2
                $extension = pathinfo($alias, PATHINFO_EXTENSION);
313 2
                $files = $template->getAssets($extension);
314 2
                $this->addToCollections($alias, $files);
315 2
            }
316 2
        }
317 3
    }
318
319
    /**
320
     * Resolves assets with absolute path
321
     *
322
     * @param string $path
323
     * @return FileAsset
324
     */
325 4
    public function resolveAbsolutePath($path)
326
    {
327 4
        if ($this->inAllowedPaths($path)) {
328 3
            $file = new SplFileInfo($path);
329 3
            if ($file->isReadable() && !$file->isDir()) {
330 3
                $filePath = $file->getRealPath();
331 3
                $mimeType = $this->getMimeResolver()->getMimeType($filePath);
332 3
                $asset = new FileAsset($filePath);
333 3
                $asset->mimetype = $mimeType;
0 ignored issues
show
Bug introduced by
The property mimetype does not seem to exist in Assetic\Asset\FileAsset.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
334 3
                return $asset;
335
            }
336
        }
337 1
        return null;
338
    }
339
340
    /**
341
     * {@inheritDoc}
342
     */
343 2
    public function resolve($name)
344
    {
345
        // Check if we are resolving an asset defined with an absolute path
346 2
        if ($name === realpath($name)) {
347 2
            return $this->resolveAbsolutePath($name);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->resolveAbsolutePath($name); of type Assetic\Asset\FileAsset|null adds the type Assetic\Asset\FileAsset to the return on line 347 which is incompatible with the return type of the parent method AssetManager\Resolver\CollectionResolver::resolve of type null|Assetic\Asset\AssetCollection.
Loading history...
348
        } // Check if it is an asset that is used globally in all pages
349 1
        elseif ($this->isGlobalAsset($name)) {
350
            $this->loadGlobalCollection($name);
351
        } // Check if it is an asset from a template
352 1
        elseif ($this->isTemplateAsset($name)) {
353 1
            $this->loadTemplateCollection($name);
354 1
        }
355 1
        $resolve = parent::resolve($name);
356 1
        if ($resolve instanceof AssetCollection) {
357 1
            $resolve->setTargetPath($this->getPublicPath() . $resolve->getTargetPath());
358 1
            if (empty($resolve->mimetype)) {
359
                $resolve->mimetype = $this->getMimeResolver()->getMimeType($name);
0 ignored issues
show
Bug introduced by
The property mimetype does not seem to exist in Assetic\Asset\AssetCollection.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
360
            }
361 1
        }
362 1
        return $resolve;
363
    }
364
365
    /**
366
     * Return the FIRST paths that contain a template with the specified name
367
     * (There should not be more than one posible template path)
368
     *
369
     * @param string $templateName
370
     * @return string
371
     */
372 3
    public function getExistantTemplatePath($templateName)
373
    {
374 3
        $paths = $this->getTemplatesPathStack();
375 3
        foreach ($paths as $path) {
376 3
            $templatePath = $path . DIRECTORY_SEPARATOR . $templateName;
377 3
            if ($this->validTemplate($templatePath)) {
378 3
                return $templatePath;
379
            }
380 3
        }
381
        return null;
382
    }
383
384
    /**
385
     * Returns true if it is a valid template
386
     *
387
     * @param string $templatePath
388
     * @return boolean
389
     */
390 3
    public function validTemplate($templatePath)
391
    {
392 3
        if (!is_dir($templatePath)) {
393 3
            return false;
394
        }
395 3
        $template = new Template();
396 3
        $template->setPath($templatePath);
397 3
        return $template->isValid();
398
    }
399
400
    /**
401
     * Returns true if the asset is in an allowed path
402
     *
403
     * @param string $name The path to the asset
404
     * @return boolean If the asset is in an allowed path will return true.
405
     */
406 4
    public function inAllowedPaths($name)
407
    {
408 4
        $allowedPaths = array_merge($this->getTemplatesPathStack(), $this->getAssetsPaths());
409 4
        foreach ($allowedPaths as $path) {
410 4
            if (DirectoryUtils::isSubpath($path, $name)) {
411 3
                return true;
412
            }
413 4
        }
414 1
        return false;
415
    }
416
417
    /**
418
     * Returns an array with the global assets path
419
     *
420
     * @return array
421
     */
422 1
    public function getGlobalAssetsPaths()
423
    {
424 1
        $ret = array();
425 1
        $assetsPaths = $this->getAssetsPaths();
426 1
        $globalFolderName = $this->getGlobalFolderName();
427 1
        foreach ($assetsPaths as $assetsPath) {
428 1
            $ret[] = $assetsPath . DIRECTORY_SEPARATOR . $globalFolderName . DIRECTORY_SEPARATOR;
429 1
        }
430 1
        return $ret;
431
    }
432
433
    /**
434
     * Generate the collections of assets for the a template.
435
     * @param string $extension
436
     * @return array|Traversable collections of assets
437
     */
438 1
    public function generateCollection($paths, $extension)
439
    {
440 1
        $ret = array();
441 1
        foreach ($paths as $path) {
442 1
            if (!is_dir($path)) {
443 1
                continue;
444
            }
445 1
            $files = DirectoryUtils::recursiveSearchByExtension($path, $extension);
446 1
            $ret = array_merge($ret, $files);
447 1
        }
448 1
        sort($ret);
449 1
        return $ret;
450
    }
451
}
452