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; |
|
|
|
|
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) { |
|
|
|
|
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; |
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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
|
|
|
|
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.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.