1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Fabiang\AsseticBundle; |
6
|
|
|
|
7
|
|
|
use Assetic\Asset\AssetCache; |
8
|
|
|
use Assetic\Asset\AssetCollection; |
9
|
|
|
use Assetic\AssetManager; |
10
|
|
|
use Assetic\AssetWriter; |
11
|
|
|
use Assetic\Cache\FilesystemCache; |
12
|
|
|
use Assetic\Contracts\Asset\AssetInterface; |
13
|
|
|
use Assetic\Contracts\Factory\Worker\WorkerInterface; |
14
|
|
|
use Assetic\Contracts\Filter\FilterInterface; |
15
|
|
|
use Assetic\Factory\AssetFactory; |
16
|
|
|
use Assetic\FilterManager as AsseticFilterManager; |
17
|
|
|
use Fabiang\AsseticBundle\Exception\InvalidArgumentException; |
18
|
|
|
use Fabiang\AsseticBundle\View\StrategyInterface; |
19
|
|
|
use Laminas\View\Renderer\RendererInterface as Renderer; |
20
|
|
|
use ReflectionClass; |
21
|
|
|
|
22
|
|
|
use function array_key_exists; |
23
|
|
|
use function array_merge; |
24
|
|
|
use function array_shift; |
25
|
|
|
use function basename; |
26
|
|
|
use function class_exists; |
27
|
|
|
use function count; |
28
|
|
|
use function filemtime; |
29
|
|
|
use function get_class; |
30
|
|
|
use function is_array; |
31
|
|
|
use function is_file; |
32
|
|
|
use function is_numeric; |
33
|
|
|
use function is_string; |
34
|
|
|
use function ltrim; |
35
|
|
|
use function sprintf; |
36
|
|
|
use function substr; |
37
|
|
|
use function umask; |
38
|
|
|
|
39
|
1 |
|
use const DIRECTORY_SEPARATOR; |
40
|
|
|
|
41
|
1 |
|
class Service |
42
|
|
|
{ |
43
|
|
|
public const DEFAULT_ROUTE_NAME = 'default'; |
44
|
3 |
|
|
45
|
|
|
protected string $routeName = self::DEFAULT_ROUTE_NAME; |
46
|
3 |
|
protected ?string $controllerName = null; |
47
|
|
|
protected ?string $actionName = null; |
48
|
|
|
protected Configuration $configuration; |
49
|
3 |
|
|
50
|
|
|
/** @var array<string, StrategyInterface> */ |
51
|
3 |
|
protected array $strategy = []; |
52
|
|
|
protected ?AssetManager $assetManager = null; |
53
|
|
|
protected ?AssetWriter $assetWriter = null; |
54
|
1 |
|
protected ?WorkerInterface $cacheBusterStrategy = null; |
55
|
|
|
protected ?AsseticFilterManager $filterManager = null; |
56
|
1 |
|
|
57
|
|
|
public function __construct(Configuration $configuration) |
58
|
|
|
{ |
59
|
6 |
|
$this->configuration = $configuration; |
60
|
|
|
} |
61
|
6 |
|
|
62
|
5 |
|
public function setRouteName(string $routeName): void |
63
|
|
|
{ |
64
|
|
|
$this->routeName = $routeName; |
65
|
6 |
|
} |
66
|
|
|
|
67
|
|
|
public function getRouteName(): string |
68
|
4 |
|
{ |
69
|
|
|
return $this->routeName; |
70
|
4 |
|
} |
71
|
4 |
|
|
72
|
4 |
|
public function setAssetManager(AssetManager $assetManager): void |
73
|
|
|
{ |
74
|
|
|
$this->assetManager = $assetManager; |
75
|
4 |
|
} |
76
|
|
|
|
77
|
|
|
public function getAssetManager(): AssetManager |
78
|
1 |
|
{ |
79
|
|
|
if (null === $this->assetManager) { |
80
|
1 |
|
$this->assetManager = new AssetManager(); |
81
|
|
|
} |
82
|
|
|
|
83
|
1 |
|
return $this->assetManager; |
84
|
|
|
} |
85
|
1 |
|
|
86
|
|
|
public function getAssetWriter(): AssetWriter |
87
|
|
|
{ |
88
|
1 |
|
if (null === $this->assetWriter) { |
89
|
|
|
$webPath = $this->configuration->getWebPath(); |
90
|
1 |
|
$this->assetWriter = new AssetWriter($webPath ?? ''); |
91
|
|
|
} |
92
|
|
|
|
93
|
1 |
|
return $this->assetWriter; |
94
|
|
|
} |
95
|
1 |
|
|
96
|
|
|
public function setAssetWriter(AssetWriter $assetWriter): void |
97
|
|
|
{ |
98
|
2 |
|
$this->assetWriter = $assetWriter; |
99
|
|
|
} |
100
|
2 |
|
|
101
|
1 |
|
public function getCacheBusterStrategy(): ?WorkerInterface |
102
|
|
|
{ |
103
|
|
|
return $this->cacheBusterStrategy; |
104
|
2 |
|
} |
105
|
|
|
|
106
|
|
|
public function setCacheBusterStrategy(?WorkerInterface $cacheBusterStrategy): void |
107
|
1 |
|
{ |
108
|
|
|
$this->cacheBusterStrategy = $cacheBusterStrategy; |
109
|
1 |
|
} |
110
|
|
|
|
111
|
|
|
public function setFilterManager(AsseticFilterManager $filterManager): void |
112
|
2 |
|
{ |
113
|
|
|
$this->filterManager = $filterManager; |
114
|
2 |
|
} |
115
|
|
|
|
116
|
|
|
public function getFilterManager(): AsseticFilterManager |
117
|
1 |
|
{ |
118
|
|
|
if (null === $this->filterManager) { |
119
|
1 |
|
$this->filterManager = new AsseticFilterManager(); |
120
|
|
|
} |
121
|
|
|
|
122
|
2 |
|
return $this->filterManager; |
123
|
|
|
} |
124
|
2 |
|
|
125
|
|
|
public function setControllerName(?string $controllerName): void |
126
|
|
|
{ |
127
|
|
|
$this->controllerName = $controllerName; |
128
|
|
|
} |
129
|
|
|
|
130
|
3 |
|
public function getControllerName(): ?string |
131
|
|
|
{ |
132
|
3 |
|
return $this->controllerName; |
133
|
3 |
|
} |
134
|
3 |
|
|
135
|
3 |
|
public function setActionName(?string $actionName): void |
136
|
3 |
|
{ |
137
|
3 |
|
$this->actionName = $actionName; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
public function getActionName(): ?string |
141
|
|
|
{ |
142
|
3 |
|
return $this->actionName; |
143
|
|
|
} |
144
|
3 |
|
|
145
|
|
|
/** |
146
|
|
|
* Build collection of assets. |
147
|
|
|
*/ |
148
|
|
|
public function build(): void |
149
|
|
|
{ |
150
|
3 |
|
$moduleConfiguration = $this->configuration->getModules(); |
151
|
|
|
foreach ($moduleConfiguration as $configuration) { |
152
|
|
|
$factory = $this->createAssetFactory($configuration); |
153
|
3 |
|
$collections = (array) $configuration['collections']; |
154
|
|
|
foreach ($collections as $name => $options) { |
155
|
3 |
|
$this->prepareCollection($options, $name, $factory); |
156
|
|
|
} |
157
|
3 |
|
} |
158
|
|
|
} |
159
|
3 |
|
|
160
|
3 |
|
private function cacheAsset(AssetInterface $asset): AssetInterface |
161
|
3 |
|
{ |
162
|
3 |
|
if ($this->configuration->getCacheEnabled()) { |
163
|
3 |
|
return new AssetCache( |
164
|
|
|
$asset, |
165
|
|
|
new FilesystemCache($this->configuration->getCachePath()) |
166
|
|
|
); |
167
|
|
|
} |
168
|
|
|
return $asset; |
169
|
3 |
|
} |
170
|
3 |
|
|
171
|
|
|
private function initFilters(array $filters): array |
172
|
|
|
{ |
173
|
|
|
$result = []; |
174
|
|
|
|
175
|
|
|
$fm = $this->getFilterManager(); |
176
|
3 |
|
|
177
|
|
|
foreach ($filters as $alias => $options) { |
178
|
|
|
$option = null; |
179
|
|
|
$name = null; |
180
|
|
|
if (is_array($options)) { |
181
|
|
|
if (! isset($options['name'])) { |
182
|
|
|
throw new InvalidArgumentException( |
183
|
3 |
|
'Filter "' . $alias . '" required option "name"' |
184
|
|
|
); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
$name = $options['name']; |
188
|
3 |
|
$option = $options['option'] ?? null; |
189
|
|
|
} elseif (is_string($options)) { |
190
|
3 |
|
$name = $options; |
191
|
3 |
|
unset($options); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
if (! is_string($name)) { |
195
|
|
|
throw new InvalidArgumentException( |
196
|
3 |
|
'Name of filter could not be found. ' |
197
|
|
|
. 'Did you provide the `name` option to the filter config?' |
198
|
|
|
); |
199
|
|
|
} |
200
|
|
|
|
201
|
3 |
|
if (is_numeric($alias)) { |
202
|
|
|
$alias = $name; |
203
|
|
|
} |
204
|
3 |
|
|
205
|
|
|
// Filter Id should have optional filter indicator "?" |
206
|
|
|
$filterId = ltrim($alias, '?'); |
207
|
3 |
|
|
208
|
|
|
if (! $fm->has($filterId)) { |
209
|
|
|
if (is_array($option) && ! empty($option)) { |
210
|
3 |
|
$r = new ReflectionClass($name); |
211
|
|
|
/** @var FilterInterface $filter */ |
212
|
|
|
$filter = $r->newInstanceArgs($option); |
213
|
|
|
} elseif ($option) { |
214
|
|
|
/** @var FilterInterface $filter */ |
215
|
|
|
$filter = new $name($option); |
216
|
|
|
} else { |
217
|
|
|
/** @var FilterInterface $filter */ |
218
|
|
|
$filter = new $name(); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
$fm->set($filterId, $filter); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
$result[] = $alias; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
return $result; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
public function setupRenderer(Renderer $renderer): bool |
231
|
|
|
{ |
232
|
|
|
$controllerConfig = $this->getControllerConfig(); |
233
|
|
|
$actionConfig = $this->getActionConfig(); |
234
|
|
|
$config = array_merge($controllerConfig, $actionConfig); |
235
|
|
|
|
236
|
|
|
if (count($config) === 0) { |
237
|
|
|
$config = $this->getRouterConfig(); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
// If we don't have any assets listed by now, or if we are mixing in |
241
|
|
|
// the default assets, then merge in the default assets to the config array |
242
|
|
|
$defaultConfig = $this->getDefaultConfig(); |
243
|
|
|
if (count($config) === 0 || (isset($defaultConfig['options']['mixin']) && $defaultConfig['options']['mixin'])) { |
244
|
|
|
$config = array_merge($defaultConfig['assets'], $config); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
if (count($config) > 0) { |
248
|
|
|
$this->setupRendererFromOptions($renderer, $config); |
249
|
|
|
|
250
|
|
|
return true; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
return false; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
public function getDefaultConfig(): array |
257
|
|
|
{ |
258
|
|
|
$defaultDefinition = $this->configuration->getDefault(); |
259
|
|
|
|
260
|
|
|
return $defaultDefinition ? $defaultDefinition : []; |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* @return array|mixed |
265
|
|
|
*/ |
266
|
|
|
public function getRouterConfig() |
267
|
|
|
{ |
268
|
|
|
$assetOptions = $this->configuration->getRoute($this->getRouteName()); |
269
|
|
|
|
270
|
|
|
return $assetOptions ? $assetOptions : []; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
public function getControllerConfig(): array |
274
|
|
|
{ |
275
|
|
|
$assetOptions = []; |
276
|
|
|
|
277
|
|
|
$controllerName = $this->getControllerName(); |
278
|
|
|
if (null !== $controllerName) { |
279
|
|
|
$assetOptions = $this->configuration->getController($controllerName); |
280
|
|
|
if ($assetOptions) { |
281
|
|
|
if (array_key_exists('actions', $assetOptions)) { |
282
|
|
|
unset($assetOptions['actions']); |
283
|
|
|
} |
284
|
|
|
} else { |
285
|
|
|
$assetOptions = []; |
286
|
|
|
} |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
return $assetOptions; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
public function getActionConfig(): array |
293
|
|
|
{ |
294
|
|
|
$actionAssets = []; |
295
|
|
|
$controllerName = $this->getControllerName(); |
296
|
|
|
if (null !== $controllerName) { |
297
|
|
|
$assetOptions = $this->configuration->getController($controllerName); |
298
|
|
|
$actionName = $this->getActionName(); |
299
|
|
|
if ( |
300
|
|
|
null !== $actionName |
301
|
|
|
&& $assetOptions |
302
|
|
|
&& array_key_exists('actions', $assetOptions) |
303
|
|
|
&& array_key_exists($actionName, $assetOptions['actions']) |
304
|
|
|
) { |
305
|
|
|
$actionAssets = $assetOptions['actions'][$actionName]; |
306
|
|
|
} |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
return $actionAssets; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
public function setupRendererFromOptions(Renderer $renderer, array $options): void |
313
|
1 |
|
{ |
314
|
|
|
if (! $this->hasStrategyForRenderer($renderer)) { |
315
|
1 |
|
throw new InvalidArgumentException(sprintf( |
316
|
|
|
'no strategy defined for renderer "%s"', |
317
|
1 |
|
$this->getRendererName($renderer) |
318
|
|
|
)); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
$strategy = $this->getStrategyForRenderer($renderer); |
322
|
|
|
if (null !== $strategy) { |
323
|
|
|
while ($assetAlias = array_shift($options)) { |
324
|
|
|
$assetAlias = ltrim($assetAlias, '@'); |
325
|
|
|
|
326
|
3 |
|
/** @var AssetInterface $asset */ |
327
|
|
|
$asset = $this->getAssetManager()->get($assetAlias); |
328
|
3 |
|
// Prepare view strategy |
329
|
1 |
|
$strategy->setupAsset($asset); |
330
|
|
|
} |
331
|
|
|
} |
332
|
2 |
|
} |
333
|
2 |
|
|
334
|
2 |
|
public function hasStrategyForRenderer(Renderer $renderer): bool |
335
|
|
|
{ |
336
|
2 |
|
$rendererName = $this->getRendererName($renderer); |
337
|
|
|
|
338
|
|
|
return (bool) $this->configuration->getStrategyNameForRenderer($rendererName); |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Get strategy to setup assets for given $renderer. |
343
|
|
|
* |
344
|
|
|
* @throws Exception\DomainException |
345
|
2 |
|
* @throws InvalidArgumentException |
346
|
1 |
|
*/ |
347
|
1 |
|
public function getStrategyForRenderer(Renderer $renderer): ?StrategyInterface |
348
|
|
|
{ |
349
|
|
|
if (! $this->hasStrategyForRenderer($renderer)) { |
350
|
|
|
return null; |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
$rendererName = $this->getRendererName($renderer); |
354
|
1 |
|
if (! isset($this->strategy[$rendererName])) { |
355
|
|
|
$strategyClass = $this->configuration->getStrategyNameForRenderer($rendererName); |
356
|
1 |
|
|
357
|
|
|
if (null === $strategyClass) { |
358
|
|
|
throw new InvalidArgumentException( |
359
|
|
|
sprintf( |
360
|
|
|
'No strategy defined for renderer "%s"', |
361
|
|
|
Renderer::class |
362
|
|
|
) |
363
|
|
|
); |
364
|
|
|
} |
365
|
1 |
|
|
366
|
|
|
if (! class_exists($strategyClass, true)) { |
367
|
|
|
throw new InvalidArgumentException( |
368
|
|
|
sprintf( |
369
|
1 |
|
'strategy class "%s" dosen\'t exists', |
370
|
1 |
|
$strategyClass |
371
|
1 |
|
) |
372
|
1 |
|
); |
373
|
1 |
|
} |
374
|
1 |
|
|
375
|
|
|
$instance = new $strategyClass(); |
376
|
1 |
|
|
377
|
|
|
if (! $instance instanceof StrategyInterface) { |
378
|
|
|
throw new Exception\DomainException( |
379
|
|
|
sprintf( |
380
|
|
|
'strategy class "%s" is not instanceof "Fabiang\AsseticBundle\View\StrategyInterface"', |
381
|
|
|
$strategyClass |
382
|
1 |
|
) |
383
|
|
|
); |
384
|
1 |
|
} |
385
|
|
|
|
386
|
|
|
$this->strategy[$rendererName] = $instance; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** @var StrategyInterface $strategy */ |
390
|
1 |
|
$strategy = $this->strategy[$rendererName]; |
391
|
|
|
$strategy->setBaseUrl($this->configuration->getBaseUrl()); |
392
|
1 |
|
$strategy->setBasePath($this->configuration->getBasePath()); |
393
|
|
|
$strategy->setDebug($this->configuration->isDebug()); |
394
|
|
|
$strategy->setCombine($this->configuration->isCombine()); |
395
|
4 |
|
$strategy->setRenderer($renderer); |
396
|
|
|
|
397
|
4 |
|
return $strategy; |
398
|
4 |
|
} |
399
|
4 |
|
|
400
|
4 |
|
/** |
401
|
4 |
|
* Get renderer name from $renderer object. |
402
|
1 |
|
*/ |
403
|
|
|
public function getRendererName(Renderer $renderer): string |
404
|
|
|
{ |
405
|
|
|
return get_class($renderer); |
406
|
|
|
} |
407
|
4 |
|
|
408
|
|
|
/** |
409
|
4 |
|
* Gets the service configuration. |
410
|
|
|
*/ |
411
|
|
|
public function getConfiguration(): Configuration |
412
|
3 |
|
{ |
413
|
|
|
return $this->configuration; |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
public function createAssetFactory(array $configuration): AssetFactory |
417
|
|
|
{ |
418
|
|
|
$factory = new AssetFactory($configuration['root_path']); |
419
|
3 |
|
$factory->setAssetManager($this->getAssetManager()); |
420
|
3 |
|
$factory->setFilterManager($this->getFilterManager()); |
421
|
|
|
$worker = $this->getCacheBusterStrategy(); |
422
|
|
|
if ($worker instanceof WorkerInterface) { |
423
|
3 |
|
$factory->addWorker($worker); |
424
|
3 |
|
} |
425
|
|
|
/** |
426
|
3 |
|
* @psalm-suppress InvalidArgument Upstream type-hint error |
427
|
|
|
*/ |
428
|
|
|
$factory->setDebug($this->configuration->isDebug()); |
429
|
3 |
|
|
430
|
3 |
|
return $factory; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
public function moveRaw( |
434
|
3 |
|
AssetCollection $asset, |
435
|
|
|
?string $targetPath, |
436
|
3 |
|
AssetFactory $factory, |
437
|
3 |
|
bool $disableSourcePath = false |
438
|
3 |
|
): void { |
439
|
3 |
|
/** @var AssetInterface $value */ |
440
|
3 |
|
foreach ($asset as $value) { |
441
|
3 |
|
$sourcePath = $value->getSourcePath() ?? ''; |
442
|
3 |
|
|
443
|
3 |
|
if ($disableSourcePath) { |
444
|
|
|
$value->setTargetPath(( $targetPath ?? '' ) . basename($sourcePath)); |
445
|
|
|
} else { |
446
|
3 |
|
$value->setTargetPath(( $targetPath ?? '' ) . $sourcePath); |
447
|
3 |
|
} |
448
|
|
|
|
449
|
|
|
$value = $this->cacheAsset($value); |
450
|
|
|
$this->writeAsset($value, $factory); |
451
|
3 |
|
} |
452
|
3 |
|
} |
453
|
3 |
|
|
454
|
|
|
public function prepareCollection(array $options, string $name, AssetFactory $factory): void |
455
|
3 |
|
{ |
456
|
|
|
$assets = $options['assets'] ?? []; |
457
|
|
|
$filters = $options['filters'] ?? []; |
458
|
3 |
|
$options = $options['options'] ?? []; |
459
|
3 |
|
$options['output'] = $options['output'] ?? $name; |
460
|
|
|
$moveRaw = isset($options['move_raw']) && $options['move_raw']; |
461
|
3 |
|
$targetPath = ! empty($options['targetPath']) ? $options['targetPath'] : ''; |
462
|
|
|
if (substr($targetPath, -1) !== DIRECTORY_SEPARATOR) { |
463
|
|
|
$targetPath .= DIRECTORY_SEPARATOR; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
$filters = $this->initFilters($filters); |
467
|
|
|
$asset = $factory->createAsset($assets, $filters, $options); |
468
|
|
|
|
469
|
|
|
// Allow to move all files 1:1 to new directory |
470
|
|
|
// its particularly useful when this assets are i.e. images. |
471
|
3 |
|
if ($moveRaw) { |
472
|
|
|
if (isset($options['disable_source_path'])) { |
473
|
|
|
$this->moveRaw($asset, $targetPath, $factory, $options['disable_source_path']); |
474
|
3 |
|
} else { |
475
|
|
|
$this->moveRaw($asset, $targetPath, $factory); |
476
|
|
|
} |
477
|
|
|
} else { |
478
|
|
|
$asset = $this->cacheAsset($asset); |
479
|
3 |
|
$this->getAssetManager()->set($name, $asset); |
480
|
|
|
// Save asset on disk |
481
|
|
|
$this->writeAsset($asset, $factory); |
482
|
|
|
} |
483
|
|
|
} |
484
|
|
|
|
485
|
3 |
|
/** |
486
|
3 |
|
* Write $asset to public directory. |
487
|
|
|
* |
488
|
3 |
|
* @param AssetInterface $asset Asset to write |
489
|
3 |
|
* @param AssetFactory $factory The factory this asset was generated with |
490
|
3 |
|
*/ |
491
|
|
|
public function writeAsset(AssetInterface $asset, AssetFactory $factory): void |
492
|
3 |
|
{ |
493
|
3 |
|
// We're not interested in saving assets on request |
494
|
3 |
|
if (! $this->configuration->getBuildOnRequest()) { |
495
|
|
|
return; |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
// Write asset on disk on every request |
499
|
3 |
|
if (! $this->configuration->getWriteIfChanged()) { |
500
|
3 |
|
$this->write($asset, $factory); |
501
|
|
|
|
502
|
|
|
return; |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
$created = false; |
506
|
|
|
$isChanged = false; |
507
|
|
|
|
508
|
3 |
|
$targetPath = $asset->getTargetPath(); |
509
|
|
|
if (null !== $targetPath) { |
510
|
3 |
|
$target = $this->configuration->getWebPath($targetPath); |
511
|
3 |
|
|
512
|
|
|
if (null !== $target) { |
|
|
|
|
513
|
|
|
$created = is_file($target); |
514
|
|
|
$isChanged = $created && filemtime($target) < $factory->getLastModified($asset); |
515
|
3 |
|
} |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
// And long requested optimization |
519
|
|
|
if (! $created || $isChanged) { |
520
|
|
|
$this->write($asset, $factory); |
521
|
3 |
|
} |
522
|
|
|
} |
523
|
|
|
|
524
|
3 |
|
/** |
525
|
|
|
* @param AssetInterface $asset Asset to write |
526
|
|
|
* @param AssetFactory $factory The factory this asset was generated with |
527
|
|
|
*/ |
528
|
|
|
protected function write(AssetInterface $asset, AssetFactory $factory): void |
529
|
|
|
{ |
530
|
|
|
$umask = $this->configuration->getUmask(); |
531
|
|
|
if (null !== $umask) { |
532
|
|
|
$umask = umask($umask); |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
if ( |
536
|
|
|
$this->configuration->isDebug() && ! $this->configuration->isCombine() && $asset instanceof AssetCollection |
537
|
|
|
) { |
538
|
|
|
foreach ($asset as $item) { |
539
|
|
|
$this->writeAsset($item, $factory); |
540
|
|
|
} |
541
|
|
|
} else { |
542
|
|
|
$this->getAssetWriter()->writeAsset($asset); |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
if (null !== $umask) { |
546
|
|
|
umask($umask); |
547
|
|
|
} |
548
|
|
|
} |
549
|
|
|
} |
550
|
|
|
|