1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace Yiisoft\Assets; |
5
|
|
|
|
6
|
|
|
use Psr\Log\LoggerInterface; |
7
|
|
|
use Yiisoft\Aliases\Aliases; |
8
|
|
|
use Yiisoft\Assets\Exception\InvalidConfigException; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* AssetManager manages asset bundle configuration and loading. |
12
|
|
|
* |
13
|
|
|
* AssetManager is configured in config/web.php. You can access that instance via $container->get(AssetManager::class). |
14
|
|
|
* |
15
|
|
|
* You can modify its configuration by adding an array to your application config under `components` as shown in the |
16
|
|
|
* following example: |
17
|
|
|
* |
18
|
|
|
* ```php |
19
|
|
|
* AssetManager::class => function (ContainerInterface $container) { |
20
|
|
|
* $aliases = $container->get(Aliases::class); |
21
|
|
|
* $assetConverterInterface = $container->get(AssetConverterInterface::class); |
22
|
|
|
* $fileSystem = $container->get(Filesystem::class); |
23
|
|
|
* $logger = $container->get(LoggerInterface::class); |
24
|
|
|
* |
25
|
|
|
* $assetManager = new AssetManager($fileSystem, $logger); |
26
|
|
|
* |
27
|
|
|
* $assetManager->setBasePath($aliases->get('@basePath')); |
28
|
|
|
* $assetManager->setBaseUrl($aliases->get('@baseUrl')); |
29
|
|
|
* $assetManager->setConverter($assetConverterInterface); |
30
|
|
|
* |
31
|
|
|
* return $assetManager; |
32
|
|
|
* }, |
33
|
|
|
* ``` |
34
|
|
|
*/ |
35
|
|
|
final class AssetManager |
36
|
|
|
{ |
37
|
|
|
private Aliases $aliases; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var array AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values |
41
|
|
|
* are the registered {@see AssetBundle} objects. |
42
|
|
|
* |
43
|
|
|
* {@see registerAssetBundle()} |
44
|
|
|
*/ |
45
|
|
|
private array $assetBundles = []; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var bool whether to append a timestamp to the URL of every published asset. When this is true, the URL of a |
49
|
|
|
* published asset may look like `/path/to/asset?v=timestamp`, where `timestamp` is the last modification time of |
50
|
|
|
* the published asset file. You normally would want to set this property to true when you have enabled HTTP caching |
51
|
|
|
* for assets, because it allows you to bust caching when the assets are updated. |
52
|
|
|
*/ |
53
|
|
|
private bool $appendTimestamp = false; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var array mapping from source asset files (keys) to target asset files (values). |
57
|
|
|
* |
58
|
|
|
* This property is provided to support fixing incorrect asset file paths in some asset bundles. When an asset |
59
|
|
|
* bundle is registered with a view, each relative asset file in its {@see AssetBundle::css|css} and |
60
|
|
|
* {@see AssetBundle::js|js} arrays will be examined against this map. If any of the keys is found to be the last |
61
|
|
|
* part of an asset file (which is prefixed with {@see AssetBundle::sourcePath} if available), the corresponding |
62
|
|
|
* value will replace the asset and be registered with the view. For example, an asset file `my/path/to/jquery.js` |
63
|
|
|
* matches a key `jquery.js`. |
64
|
|
|
* |
65
|
|
|
* Note that the target asset files should be absolute URLs, domain relative URLs (starting from '/') or paths |
66
|
|
|
* relative to {@see baseUrl} and {@see basePath}. |
67
|
|
|
* |
68
|
|
|
* In the following example, any assets ending with `jquery.min.js` will be replaced with `jquery/dist/jquery.js` |
69
|
|
|
* which is relative to {@see baseUrl} and {@see basePath}. |
70
|
|
|
* |
71
|
|
|
* ```php |
72
|
|
|
* [ |
73
|
|
|
* 'jquery.min.js' => 'jquery/dist/jquery.js', |
74
|
|
|
* ] |
75
|
|
|
* ``` |
76
|
|
|
*/ |
77
|
|
|
private array $assetMap = []; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @var AssetPublisher published assets |
81
|
|
|
*/ |
82
|
|
|
private AssetPublisher $publish; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @var string|null the root directory storing the published asset files. |
86
|
|
|
*/ |
87
|
|
|
private ?string $basePath = null; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @var string|null the base URL through which the published asset files can be accessed. |
91
|
|
|
*/ |
92
|
|
|
private ?string $baseUrl = null; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @var array list of asset bundle configurations. This property is provided to customize asset bundles. |
96
|
|
|
* When a bundle is being loaded by {@see getBundle()}, if it has a corresponding configuration specified here, the |
97
|
|
|
* configuration will be applied to the bundle. |
98
|
|
|
* |
99
|
|
|
* The array keys are the asset bundle names, which typically are asset bundle class names without leading |
100
|
|
|
* backslash. The array values are the corresponding configurations. If a value is false, it means the corresponding |
101
|
|
|
* asset bundle is disabled and {@see getBundle()} should return null. |
102
|
|
|
* |
103
|
|
|
* If this property is false, it means the whole asset bundle feature is disabled and {@see {getBundle()} will |
104
|
|
|
* always return null. |
105
|
|
|
*/ |
106
|
|
|
private array $bundles = []; |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* AssetConverter component. |
110
|
|
|
* |
111
|
|
|
* @var AssetConverterInterface $converter |
112
|
|
|
*/ |
113
|
|
|
private AssetConverterInterface $converter; |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @var array the registered CSS files. |
117
|
|
|
* |
118
|
|
|
* {@see registerCssFile()} |
119
|
|
|
*/ |
120
|
|
|
private array $cssFiles = []; |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @var int the permission to be set for newly generated asset directories. This value will be used by PHP chmod() |
124
|
|
|
* function. No umask will be applied. Defaults to 0775, meaning the directory is read-writable by owner |
125
|
|
|
* and group, but read-only for other users. |
126
|
|
|
*/ |
127
|
|
|
private int $dirMode = 0775; |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @var array $dummyBundles |
131
|
|
|
*/ |
132
|
|
|
private array $dummyBundles; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @var int the permission to be set for newly published asset files. This value will be used by PHP chmod() |
136
|
|
|
* function. No umask will be applied. If not set, the permission will be determined by the current |
137
|
|
|
* environment. |
138
|
|
|
*/ |
139
|
|
|
private int $fileMode = 0755; |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* @var bool whether the directory being published should be copied even if it is found in the target directory. |
143
|
|
|
* This option is used only when publishing a directory. You may want to set this to be `true` during the |
144
|
|
|
* development stage to make sure the published directory is always up-to-date. Do not set this to true |
145
|
|
|
* on production servers as it will significantly degrade the performance. |
146
|
|
|
*/ |
147
|
|
|
private bool $forceCopy = false; |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* @var callable a callback that will be called to produce hash for asset directory generation. The signature of the |
151
|
|
|
* callback should be as follows: |
152
|
|
|
* |
153
|
|
|
* ``` |
154
|
|
|
* function ($path) |
155
|
|
|
* ``` |
156
|
|
|
* |
157
|
|
|
* where `$path` is the asset path. Note that the `$path` can be either directory where the asset files reside or a |
158
|
|
|
* single file. For a CSS file that uses relative path in `url()`, the hash implementation should use the directory |
159
|
|
|
* path of the file instead of the file path to include the relative asset files in the copying. |
160
|
|
|
* |
161
|
|
|
* If this is not set, the asset manager will use the default CRC32 and filemtime in the `hash` method. |
162
|
|
|
* |
163
|
|
|
* Example of an implementation using MD4 hash: |
164
|
|
|
* |
165
|
|
|
* ```php |
166
|
|
|
* function ($path) { |
167
|
|
|
* return hash('md4', $path); |
168
|
|
|
* } |
169
|
|
|
* ``` |
170
|
|
|
*/ |
171
|
|
|
private $hashCallback; |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @var bool whether to use symbolic link to publish asset files. Defaults to false, meaning asset files are copied |
175
|
|
|
* to {@see basePath}. Using symbolic links has the benefit that the published assets will always be |
176
|
|
|
* consistent with the source assets and there is no copy operation required. This is especially useful |
177
|
|
|
* during development. |
178
|
|
|
* |
179
|
|
|
* However, there are special requirements for hosting environments in order to use symbolic links. In particular, |
180
|
|
|
* symbolic links are supported only on Linux/Unix, and Windows Vista/2008 or greater. |
181
|
|
|
* |
182
|
|
|
* Moreover, some Web servers need to be properly configured so that the linked assets are accessible to Web users. |
183
|
|
|
* For example, for Apache Web server, the following configuration directive should be added for the Web folder: |
184
|
|
|
* |
185
|
|
|
* ```apache |
186
|
|
|
* Options FollowSymLinks |
187
|
|
|
* ``` |
188
|
|
|
*/ |
189
|
|
|
private bool $linkAssets = false; |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* @var array the registered JS files. |
193
|
|
|
* |
194
|
|
|
* {@see registerJsFile()} |
195
|
|
|
*/ |
196
|
|
|
private array $jsFiles = []; |
197
|
|
|
|
198
|
|
|
private LoggerInterface $logger; |
199
|
|
|
|
200
|
54 |
|
public function __construct(Aliases $aliases, LoggerInterface $logger) |
201
|
|
|
{ |
202
|
54 |
|
$this->aliases = $aliases; |
203
|
54 |
|
$this->logger = $logger; |
204
|
54 |
|
$this->publish = $this->getPublish(); |
205
|
54 |
|
} |
206
|
|
|
|
207
|
27 |
|
public function getAliases(): Aliases |
208
|
|
|
{ |
209
|
27 |
|
return $this->aliases; |
210
|
|
|
} |
211
|
|
|
|
212
|
20 |
|
public function getAssetMap(): array |
213
|
|
|
{ |
214
|
20 |
|
return $this->assetMap; |
215
|
|
|
} |
216
|
|
|
|
217
|
17 |
|
public function getAppendTimestamp(): bool |
218
|
|
|
{ |
219
|
17 |
|
return $this->appendTimestamp; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Registers the asset manager being used by this view object. |
224
|
|
|
* |
225
|
|
|
* @return array the asset manager. Defaults to the "assetManager" application component. |
226
|
|
|
*/ |
227
|
22 |
|
public function getAssetBundles(): array |
228
|
|
|
{ |
229
|
22 |
|
return $this->assetBundles; |
230
|
|
|
} |
231
|
|
|
|
232
|
2 |
|
public function getBasePath(): ?string |
233
|
|
|
{ |
234
|
2 |
|
if (!empty($this->basePath)) { |
235
|
1 |
|
$this->basePath = $this->aliases->get($this->basePath); |
|
|
|
|
236
|
|
|
} |
237
|
|
|
|
238
|
2 |
|
return $this->basePath; |
239
|
|
|
} |
240
|
|
|
|
241
|
1 |
|
public function getBaseUrl(): ?string |
242
|
|
|
{ |
243
|
1 |
|
if (!empty($this->baseUrl)) { |
244
|
|
|
$this->baseUrl = $this->aliases->get($this->baseUrl); |
|
|
|
|
245
|
|
|
} |
246
|
|
|
|
247
|
1 |
|
return $this->baseUrl; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Returns the named asset bundle. |
252
|
|
|
* |
253
|
|
|
* This method will first look for the bundle in {@see bundles()}. If not found, it will treat `$name` as the class |
254
|
|
|
* of the asset bundle and create a new instance of it. |
255
|
|
|
* |
256
|
|
|
* @param string $name the class name of the asset bundle (without the leading backslash). |
257
|
|
|
* |
258
|
|
|
* @return AssetBundle the asset bundle instance |
259
|
|
|
* |
260
|
|
|
* @throws \InvalidArgumentException |
261
|
|
|
* @throws InvalidConfigException |
262
|
|
|
*/ |
263
|
27 |
|
public function getBundle(string $name): AssetBundle |
264
|
|
|
{ |
265
|
27 |
|
if (!isset($this->bundles[$name])) { |
266
|
25 |
|
return $this->bundles[$name] = $this->publish->loadBundle($name, []); |
267
|
|
|
} |
268
|
|
|
|
269
|
13 |
|
if ($this->bundles[$name] instanceof AssetBundle) { |
270
|
|
|
return $this->bundles[$name]; |
271
|
|
|
} |
272
|
|
|
|
273
|
13 |
|
if (\is_array($this->bundles[$name])) { |
274
|
13 |
|
return $this->bundles[$name] = $this->publish->loadBundle($name, $this->bundles[$name]); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
if ($this->bundles[$name] === false) { |
278
|
|
|
return $this->loadDummyBundle($name); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
throw new \InvalidArgumentException("Invalid asset bundle configuration: $name"); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Returns the asset converter. |
286
|
|
|
* |
287
|
|
|
* @return AssetConverterInterface the asset converter. |
288
|
|
|
*/ |
289
|
1 |
|
public function getConverter(): AssetConverterInterface |
290
|
|
|
{ |
291
|
1 |
|
if (empty($this->converter)) { |
292
|
1 |
|
$this->converter = new AssetConverter($this->aliases, $this->logger); |
293
|
|
|
} |
294
|
|
|
|
295
|
1 |
|
return $this->converter; |
296
|
|
|
} |
297
|
|
|
|
298
|
14 |
|
public function getCssFiles(): array |
299
|
|
|
{ |
300
|
14 |
|
return $this->cssFiles; |
301
|
|
|
} |
302
|
|
|
|
303
|
7 |
|
public function getDirMode(): int |
304
|
|
|
{ |
305
|
7 |
|
return $this->dirMode; |
306
|
|
|
} |
307
|
|
|
|
308
|
7 |
|
public function getFileMode(): int |
309
|
|
|
{ |
310
|
7 |
|
return $this->fileMode; |
311
|
|
|
} |
312
|
|
|
|
313
|
7 |
|
public function getForceCopy(): bool |
314
|
|
|
{ |
315
|
7 |
|
return $this->forceCopy; |
316
|
|
|
} |
317
|
|
|
|
318
|
23 |
|
public function getJsFiles(): array |
319
|
|
|
{ |
320
|
23 |
|
return $this->jsFiles; |
321
|
|
|
} |
322
|
|
|
|
323
|
7 |
|
public function getLinkAssets(): bool |
324
|
|
|
{ |
325
|
7 |
|
return $this->linkAssets; |
326
|
|
|
} |
327
|
|
|
|
328
|
7 |
|
public function getHashCallback(): ?callable |
329
|
|
|
{ |
330
|
7 |
|
return $this->hashCallback; |
331
|
|
|
} |
332
|
|
|
|
333
|
54 |
|
public function getPublish(): AssetPublisher |
334
|
|
|
{ |
335
|
54 |
|
if (empty($this->publish)) { |
336
|
54 |
|
$this->publish = new AssetPublisher($this); |
337
|
|
|
} |
338
|
|
|
|
339
|
54 |
|
return $this->publish; |
340
|
|
|
} |
341
|
|
|
|
342
|
2 |
|
public function getPublishedPath(?string $sourcePath): ?string |
343
|
|
|
{ |
344
|
2 |
|
return $this->publish->getPublishedPath($sourcePath); |
|
|
|
|
345
|
|
|
} |
346
|
|
|
|
347
|
2 |
|
public function getPublishedUrl(?string $sourcePath): ?string |
348
|
|
|
{ |
349
|
2 |
|
return $this->publish->getPublishedUrl($sourcePath); |
|
|
|
|
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Set appendTimestamp. |
354
|
|
|
* |
355
|
|
|
* @param bool $value |
356
|
|
|
* |
357
|
|
|
* @return void |
358
|
|
|
* |
359
|
|
|
* {@see appendTimestamp} |
360
|
|
|
*/ |
361
|
21 |
|
public function setAppendTimestamp(bool $value): void |
362
|
|
|
{ |
363
|
21 |
|
$this->appendTimestamp = $value; |
364
|
21 |
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Set assetMap. |
368
|
|
|
* |
369
|
|
|
* @param array $value |
370
|
|
|
* |
371
|
|
|
* @return void |
372
|
|
|
* |
373
|
|
|
* {@see assetMap} |
374
|
|
|
*/ |
375
|
1 |
|
public function setAssetMap(array $value): void |
376
|
|
|
{ |
377
|
1 |
|
$this->assetMap = $value; |
378
|
1 |
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Set basePath. |
382
|
|
|
* |
383
|
|
|
* @param string|null $value |
384
|
|
|
* |
385
|
|
|
* @return void |
386
|
|
|
* |
387
|
|
|
* {@see basePath} |
388
|
|
|
*/ |
389
|
3 |
|
public function setBasePath(?string $value): void |
390
|
|
|
{ |
391
|
3 |
|
$this->basePath = $value; |
392
|
3 |
|
} |
393
|
|
|
|
394
|
|
|
/** |
395
|
|
|
* Set baseUrl. |
396
|
|
|
* |
397
|
|
|
* @param string|null $value |
398
|
|
|
* |
399
|
|
|
* @return void |
400
|
|
|
* |
401
|
|
|
* {@see baseUrl} |
402
|
|
|
*/ |
403
|
1 |
|
public function setBaseUrl(?string $value): void |
404
|
|
|
{ |
405
|
1 |
|
$this->baseUrl = $value; |
406
|
1 |
|
} |
407
|
|
|
|
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Set bundles. |
411
|
|
|
* |
412
|
|
|
* @param array $value |
413
|
|
|
* |
414
|
|
|
* @return void |
415
|
|
|
* |
416
|
|
|
* {@see bundles} |
417
|
|
|
*/ |
418
|
13 |
|
public function setBundles(array $value): void |
419
|
|
|
{ |
420
|
13 |
|
$this->bundles = $value; |
421
|
13 |
|
} |
422
|
|
|
|
423
|
|
|
/** |
424
|
|
|
* Sets the asset converter. |
425
|
|
|
* |
426
|
|
|
* @param AssetConverterInterface $value the asset converter. This can be eitheran object implementing the |
427
|
|
|
* {@see AssetConverterInterface}, or a configuration array that can be used |
428
|
|
|
* to create the asset converter object. |
429
|
|
|
*/ |
430
|
|
|
public function setConverter(AssetConverterInterface $value): void |
431
|
|
|
{ |
432
|
|
|
$this->converter = $value; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
/** |
436
|
|
|
* Set hashCallback. |
437
|
|
|
* |
438
|
|
|
* @param callable $value |
439
|
|
|
* |
440
|
|
|
* @return void |
441
|
|
|
* |
442
|
|
|
* {@see hashCallback} |
443
|
|
|
*/ |
444
|
1 |
|
public function setHashCallback(callable $value): void |
445
|
|
|
{ |
446
|
1 |
|
$this->hashCallback = $value; |
447
|
1 |
|
} |
448
|
|
|
|
449
|
25 |
|
public function register(array $names, ?int $position = null): void |
450
|
|
|
{ |
451
|
25 |
|
foreach ($names as $name) { |
452
|
25 |
|
$this->registerAssetBundle($name, $position); |
453
|
20 |
|
$this->registerFiles($name); |
454
|
|
|
} |
455
|
17 |
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Registers a CSS file. |
459
|
|
|
* |
460
|
|
|
* This method should be used for simple registration of CSS files. If you want to use features of |
461
|
|
|
* {@see AssetManager} like appending timestamps to the URL and file publishing options, use {@see AssetBundle} |
462
|
|
|
* and {@see registerAssetBundle()} instead. |
463
|
|
|
* |
464
|
|
|
* @param string $url the CSS file to be registered. |
465
|
|
|
* @param array $options the HTML attributes for the link tag. Please refer to {@see \Yiisoft\Html\Html::cssFile()} |
466
|
|
|
* for the supported options. The following options are specially handled and are not treated as HTML |
467
|
|
|
* attributes: |
468
|
|
|
* |
469
|
|
|
* - `depends`: array, specifies the names of the asset bundles that this CSS file depends on. |
470
|
|
|
* |
471
|
|
|
* @param string $key the key that identifies the CSS script file. If null, it will use $url as the key. If two CSS |
472
|
|
|
* files are registered with the same key, the latter will overwrite the former. |
473
|
|
|
* |
474
|
|
|
* @return void |
475
|
|
|
*/ |
476
|
24 |
|
public function registerCssFile(string $url, array $options = [], string $key = null): void |
477
|
|
|
{ |
478
|
24 |
|
$key = $key ?: $url; |
479
|
|
|
|
480
|
24 |
|
$this->cssFiles[$key]['url'] = $url; |
481
|
24 |
|
$this->cssFiles[$key]['attributes'] = $options; |
482
|
24 |
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Registers a JS file. |
486
|
|
|
* |
487
|
|
|
* This method should be used for simple registration of JS files. If you want to use features of |
488
|
|
|
* {@see AssetManager} like appending timestamps to the URL and file publishing options, use {@see AssetBundle} |
489
|
|
|
* and {@see registerAssetBundle()} instead. |
490
|
|
|
* |
491
|
|
|
* @param string $url the JS file to be registered. |
492
|
|
|
* @param array $options the HTML attributes for the script tag. The following options are specially handled and |
493
|
|
|
* are not treated as HTML attributes: |
494
|
|
|
* |
495
|
|
|
* - `depends`: array, specifies the names of the asset bundles that this JS file depends on. |
496
|
|
|
* - `position`: specifies where the JS script tag should be inserted in a page. The possible values are: |
497
|
|
|
* * [[POS_HEAD]]: in the head section |
498
|
|
|
* * [[POS_BEGIN]]: at the beginning of the body section |
499
|
|
|
* * [[POS_END]]: at the end of the body section. This is the default value. |
500
|
|
|
* |
501
|
|
|
* Please refer to {@see \Yiisoft\Html\Html::jsFile()} for other supported options. |
502
|
|
|
* |
503
|
|
|
* @param string $key the key that identifies the JS script file. If null, it will use $url as the key. If two JS |
504
|
|
|
* files are registered with the same key at the same position, the latter will overwrite the former. |
505
|
|
|
* Note that position option takes precedence, thus files registered with the same key, but different |
506
|
|
|
* position option will not override each other. |
507
|
|
|
* |
508
|
|
|
* @return void |
509
|
|
|
*/ |
510
|
29 |
|
public function registerJsFile(string $url, array $options = [], string $key = null): void |
511
|
|
|
{ |
512
|
29 |
|
$key = $key ?: $url; |
513
|
|
|
|
514
|
29 |
|
if (!\array_key_exists('position', $options)) { |
515
|
24 |
|
$options = array_merge(['position' => 3], $options); |
516
|
|
|
} |
517
|
|
|
|
518
|
29 |
|
$this->jsFiles[$key]['url'] = $url; |
519
|
29 |
|
$this->jsFiles[$key]['attributes'] = $options; |
520
|
29 |
|
} |
521
|
|
|
|
522
|
|
|
/** |
523
|
|
|
* Registers the named asset bundle. |
524
|
|
|
* |
525
|
|
|
* All dependent asset bundles will be registered. |
526
|
|
|
* |
527
|
|
|
* @param string $name the class name of the asset bundle (without the leading backslash) |
528
|
|
|
* @param int|null $position if set, this forces a minimum position for javascript files. This will adjust depending |
529
|
|
|
* assets javascript file position or fail if requirement can not be met. If this is null, asset |
530
|
|
|
* bundles position settings will not be changed. |
531
|
|
|
* |
532
|
|
|
* {@see registerJsFile()} for more details on javascript position. |
533
|
|
|
* |
534
|
|
|
* @return AssetBundle the registered asset bundle instance |
535
|
|
|
* @throws InvalidConfigException |
536
|
|
|
* |
537
|
|
|
* @throws \RuntimeException if the asset bundle does not exist or a circular dependency is detected |
538
|
|
|
*/ |
539
|
25 |
|
private function registerAssetBundle(string $name, ?int $position = null): AssetBundle |
540
|
|
|
{ |
541
|
25 |
|
if (!isset($this->assetBundles[$name])) { |
542
|
25 |
|
$bundle = $this->getBundle($name); |
543
|
|
|
|
544
|
23 |
|
$this->assetBundles[$name] = false; |
545
|
|
|
|
546
|
|
|
// register dependencies |
547
|
23 |
|
$pos = $bundle->jsOptions['position'] ?? null; |
548
|
|
|
|
549
|
23 |
|
foreach ($bundle->depends as $dep) { |
550
|
19 |
|
$this->registerAssetBundle($dep, $pos); |
551
|
|
|
} |
552
|
|
|
|
553
|
22 |
|
$this->assetBundles[$name] = $bundle; |
554
|
9 |
|
} elseif ($this->assetBundles[$name] === false) { |
555
|
1 |
|
throw new \RuntimeException("A circular dependency is detected for bundle '$name'."); |
556
|
|
|
} else { |
557
|
8 |
|
$bundle = $this->assetBundles[$name]; |
558
|
|
|
} |
559
|
|
|
|
560
|
22 |
|
if ($position !== null) { |
561
|
10 |
|
$pos = $bundle->jsOptions['position'] ?? null; |
562
|
|
|
|
563
|
10 |
|
if ($pos === null) { |
564
|
10 |
|
$bundle->jsOptions['position'] = $pos = $position; |
565
|
4 |
|
} elseif ($pos > $position) { |
566
|
4 |
|
throw new \RuntimeException( |
567
|
4 |
|
"An asset bundle that depends on '$name' has a higher javascript file " . |
568
|
4 |
|
"position configured than '$name'." |
569
|
|
|
); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
// update position for all dependencies |
573
|
10 |
|
foreach ($bundle->depends as $dep) { |
574
|
6 |
|
$this->registerAssetBundle($dep, $pos); |
575
|
|
|
} |
576
|
|
|
} |
577
|
22 |
|
return $bundle; |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
/** |
581
|
|
|
* Loads dummy bundle by name. |
582
|
|
|
* |
583
|
|
|
* @param string $name AssetBunle name class. |
584
|
|
|
* |
585
|
|
|
* @return AssetBundle |
586
|
|
|
* @throws InvalidConfigException |
587
|
|
|
*/ |
588
|
|
|
private function loadDummyBundle(string $name): AssetBundle |
589
|
|
|
{ |
590
|
|
|
if (!isset($this->dummyBundles[$name])) { |
591
|
|
|
$this->dummyBundles[$name] = $this->publish->loadBundle($name, [ |
592
|
|
|
'sourcePath' => null, |
593
|
|
|
'js' => [], |
594
|
|
|
'css' => [], |
595
|
|
|
'depends' => [], |
596
|
|
|
]); |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
return $this->dummyBundles[$name]; |
600
|
|
|
} |
601
|
|
|
|
602
|
20 |
|
private function registerFiles(string $name): void |
603
|
|
|
{ |
604
|
20 |
|
if (!isset($this->assetBundles[$name])) { |
605
|
|
|
return; |
606
|
|
|
} |
607
|
|
|
|
608
|
20 |
|
$bundle = $this->assetBundles[$name]; |
609
|
|
|
|
610
|
20 |
|
foreach ($bundle->depends as $dep) { |
611
|
16 |
|
$this->registerFiles($dep); |
612
|
|
|
} |
613
|
|
|
|
614
|
20 |
|
$this->publish->registerAssetFiles($bundle); |
615
|
19 |
|
} |
616
|
|
|
} |
617
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.