1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Botble\Assets; |
4
|
|
|
|
5
|
|
|
use Illuminate\Config\Repository; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class Assets. |
9
|
|
|
* |
10
|
|
|
* @since 22/07/2015 11:23 PM |
11
|
|
|
*/ |
12
|
|
|
class Assets |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* @var Repository |
16
|
|
|
*/ |
17
|
|
|
protected $config; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @var HtmlBuilder |
21
|
|
|
*/ |
22
|
|
|
protected $htmlBuilder; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var array |
26
|
|
|
*/ |
27
|
|
|
protected $scripts = []; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var array |
31
|
|
|
*/ |
32
|
|
|
protected $styles = []; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var array |
36
|
|
|
*/ |
37
|
|
|
protected $appendedScripts = [ |
38
|
|
|
'header' => [], |
39
|
|
|
'footer' => [], |
40
|
|
|
]; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var array |
44
|
|
|
*/ |
45
|
|
|
protected $appendedStyles = []; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
protected $build = ''; |
51
|
|
|
|
52
|
|
|
const ASSETS_SCRIPT_POSITION_HEADER = 'header'; |
53
|
|
|
|
54
|
|
|
const ASSETS_SCRIPT_POSITION_FOOTER = 'footer'; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Assets constructor. |
58
|
|
|
* |
59
|
|
|
* @param Repository $config |
60
|
|
|
* @param HtmlBuilder $htmlBuilder |
61
|
|
|
*/ |
62
|
|
|
public function __construct(Repository $config, HtmlBuilder $htmlBuilder) |
63
|
|
|
{ |
64
|
|
|
$this->config = $config->get('assets'); |
65
|
|
|
|
66
|
|
|
$this->scripts = $this->config['scripts']; |
67
|
|
|
|
68
|
|
|
$this->styles = $this->config['styles']; |
69
|
|
|
|
70
|
|
|
$this->htmlBuilder = $htmlBuilder; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Add scripts to current module. |
75
|
|
|
* |
76
|
|
|
* @param array $assets |
77
|
|
|
* @return $this |
78
|
|
|
*/ |
79
|
|
|
public function addScripts($assets) |
80
|
|
|
{ |
81
|
|
|
$this->scripts = array_merge($this->scripts, (array)$assets); |
82
|
|
|
|
83
|
|
|
return $this; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Add Css to current module. |
88
|
|
|
* |
89
|
|
|
* @param array $assets |
90
|
|
|
* @return $this |
91
|
|
|
*/ |
92
|
|
|
public function addStyles($assets) |
93
|
|
|
{ |
94
|
|
|
$this->styles = array_merge($this->styles, (array)$assets); |
95
|
|
|
|
96
|
|
|
return $this; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Add styles directly. |
101
|
|
|
* |
102
|
|
|
* @param array|string $assets |
103
|
|
|
* @return $this |
104
|
|
|
*/ |
105
|
|
|
public function addStylesDirectly($assets) |
106
|
|
|
{ |
107
|
|
View Code Duplication |
foreach ((array)$assets as &$item) { |
|
|
|
|
108
|
|
|
if (!in_array($item, $this->appendedStyles)) { |
109
|
|
|
$this->appendedStyles[] = [ |
110
|
|
|
'src' => $item, |
111
|
|
|
'attributes' => [], |
112
|
|
|
]; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
return $this; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Add scripts directly. |
121
|
|
|
* |
122
|
|
|
* @param string|array $assets |
123
|
|
|
* @param string $location |
124
|
|
|
* @return $this |
125
|
|
|
*/ |
126
|
|
|
public function addScriptsDirectly($assets, $location = self::ASSETS_SCRIPT_POSITION_FOOTER) |
127
|
|
|
{ |
128
|
|
View Code Duplication |
foreach ((array)$assets as &$item) { |
|
|
|
|
129
|
|
|
if (!in_array($item, $this->appendedScripts[$location])) { |
130
|
|
|
$this->appendedScripts[$location][] = [ |
131
|
|
|
'src' => $item, |
132
|
|
|
'attributes' => [], |
133
|
|
|
]; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
return $this; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Remove Css to current module. |
142
|
|
|
* |
143
|
|
|
* @param array $assets |
144
|
|
|
* @return $this |
145
|
|
|
*/ |
146
|
|
|
public function removeStyles($assets) |
147
|
|
|
{ |
148
|
|
|
foreach ((array)$assets as $rem) { |
149
|
|
|
array_forget($this->styles, array_search($rem, $this->styles)); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return $this; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Add scripts. |
157
|
|
|
* |
158
|
|
|
* @param array $assets |
159
|
|
|
* @return $this |
160
|
|
|
*/ |
161
|
|
|
public function removeScripts($assets) |
162
|
|
|
{ |
163
|
|
|
foreach ((array)$assets as $rem) { |
164
|
|
|
array_forget($this->scripts, array_search($rem, $this->scripts)); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return $this; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Get All scripts in current module. |
172
|
|
|
* |
173
|
|
|
* @param string $location `header` or `footer` |
174
|
|
|
* @return array |
175
|
|
|
*/ |
176
|
|
|
public function getScripts($location = null) |
177
|
|
|
{ |
178
|
|
|
$scripts = []; |
179
|
|
|
|
180
|
|
|
$this->scripts = array_unique($this->scripts); |
181
|
|
|
|
182
|
|
|
foreach ($this->scripts as $script) { |
183
|
|
|
$configName = 'resources.scripts.' . $script; |
184
|
|
|
|
185
|
|
|
if (!empty($location) && $location !== array_get($this->config, $configName . '.location')) { |
186
|
|
|
continue; // Skip assets that don't match this location |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
$scripts = array_merge($scripts, $this->getScriptItem($location, $configName, $script)); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
if (isset($this->appendedScripts[$location])) { |
193
|
|
|
$scripts = array_merge($scripts, $this->appendedScripts[$location]); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return $scripts; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Get All CSS in current module. |
201
|
|
|
* |
202
|
|
|
* @param array $lastStyles Append last CSS to current module |
203
|
|
|
* @return array |
204
|
|
|
*/ |
205
|
|
|
public function getStyles($lastStyles = []) |
206
|
|
|
{ |
207
|
|
|
$styles = []; |
208
|
|
|
if (!empty($lastStyles)) { |
209
|
|
|
$this->styles = array_merge($this->styles, $lastStyles); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
$this->styles = array_unique($this->styles); |
213
|
|
|
|
214
|
|
|
foreach ($this->styles as $style) { |
215
|
|
|
$configName = 'resources.styles.' . $style; |
216
|
|
|
|
217
|
|
|
$styles = array_merge($styles, $this->getSource($configName)); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
return array_merge($styles, $this->appendedStyles); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Convert script to html. |
225
|
|
|
* |
226
|
|
|
* @param string $name |
227
|
|
|
* @return string|null |
228
|
|
|
*/ |
229
|
|
|
public function scriptToHtml($name) |
230
|
|
|
{ |
231
|
|
|
return $this->itemToHtml($name, 'script'); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Convert style to html. |
236
|
|
|
* |
237
|
|
|
* @param string $name |
238
|
|
|
*/ |
239
|
|
|
public function styleToHtml($name) |
240
|
|
|
{ |
241
|
|
|
return $this->itemToHtml($name, 'style'); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* Render assets to header. |
246
|
|
|
* |
247
|
|
|
* @param array $lastStyles |
248
|
|
|
* @return string |
249
|
|
|
* @throws \Throwable |
250
|
|
|
*/ |
251
|
|
|
public function renderHeader($lastStyles = []) |
252
|
|
|
{ |
253
|
|
|
$styles = $this->getStyles($lastStyles); |
254
|
|
|
|
255
|
|
|
$headScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_HEADER); |
256
|
|
|
|
257
|
|
|
return view('assets::header', compact('styles', 'headScripts'))->render(); |
|
|
|
|
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Render assets to footer. |
262
|
|
|
* |
263
|
|
|
* @return string |
264
|
|
|
* @throws \Throwable |
265
|
|
|
*/ |
266
|
|
|
public function renderFooter() |
267
|
|
|
{ |
268
|
|
|
$bodyScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_FOOTER); |
269
|
|
|
|
270
|
|
|
return view('assets::footer', compact('bodyScripts'))->render(); |
|
|
|
|
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Get script item. |
275
|
|
|
* |
276
|
|
|
* @param string $location |
277
|
|
|
* @param string $configName |
278
|
|
|
* @param string $script |
279
|
|
|
* @return array |
280
|
|
|
*/ |
281
|
|
|
protected function getScriptItem($location, $configName, $script) |
282
|
|
|
{ |
283
|
|
|
$scripts = $this->getSource($configName, $location); |
284
|
|
|
|
285
|
|
|
if (array_get($this->config, $configName . '.include_style')) { |
286
|
|
|
$this->addStyles([$script]); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
return $scripts; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Fallback to local script if CDN fails. |
294
|
|
|
* |
295
|
|
|
* @param string $src |
296
|
|
|
* @param string $configName |
297
|
|
|
* @return array |
298
|
|
|
*/ |
299
|
|
|
protected function getFallbackScript($src, $configName) |
300
|
|
|
{ |
301
|
|
|
return [ |
302
|
|
|
'src' => $src, |
303
|
|
|
'fallback' => array_get($this->config, $configName . '.fallback'), |
304
|
|
|
'fallbackURL' => array_get($this->config, $configName . '.src.local'), |
305
|
|
|
]; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Convert item to html. |
310
|
|
|
* |
311
|
|
|
* @param string $name |
312
|
|
|
* @param string $type |
313
|
|
|
* @return null|string |
314
|
|
|
*/ |
315
|
|
|
protected function itemToHtml($name, $type = 'style') |
316
|
|
|
{ |
317
|
|
|
$html = ''; |
318
|
|
|
|
319
|
|
|
if (!in_array($type, ['style', 'script'])) { |
320
|
|
|
return $html; |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
$configName = 'resources.' . $type . 's.' . $name; |
324
|
|
|
|
325
|
|
|
if (!array_has($this->config, $configName)) { |
326
|
|
|
return $html; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
$src = $this->getSourceUrl($configName); |
330
|
|
|
|
331
|
|
|
foreach ((array)$src as $item) { |
332
|
|
|
$html .= $this->{$type}($item, ['class' => 'hidden'])->toHtml(); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
return $html; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* @param $configName |
340
|
|
|
* @return null|string|array |
341
|
|
|
*/ |
342
|
|
|
protected function getSourceUrl($configName) |
343
|
|
|
{ |
344
|
|
|
if (!array_has($this->config, $configName)) { |
345
|
|
|
return null; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
$src = array_get($this->config, $configName . '.src.local'); |
349
|
|
|
|
350
|
|
|
if ($this->isUsingCdn($configName)) { |
351
|
|
|
$src = array_get($this->config, $configName . '.src.cdn'); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
return $src; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* @param $configName |
359
|
|
|
* @return bool |
360
|
|
|
*/ |
361
|
|
|
protected function isUsingCdn($configName) |
362
|
|
|
{ |
363
|
|
|
return array_get($this->config, $configName . '.use_cdn', false) && !$this->config['offline']; |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* @param $configName |
368
|
|
|
* @return array |
369
|
|
|
*/ |
370
|
|
|
protected function getSource($configName, $location = null) |
371
|
|
|
{ |
372
|
|
|
$isUsingCdn = $this->isUsingCdn($configName); |
373
|
|
|
|
374
|
|
|
$attributes = $isUsingCdn ? [] : array_get($this->config, $configName . '.attributes', []); |
375
|
|
|
|
376
|
|
|
$src = $this->getSourceUrl($configName); |
377
|
|
|
|
378
|
|
|
$scripts = []; |
379
|
|
|
|
380
|
|
|
foreach ((array)$src as $s) { |
381
|
|
|
$scripts[] = [ |
382
|
|
|
'src' => $s, |
383
|
|
|
'attributes' => $attributes, |
384
|
|
|
]; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
if (empty($src) && |
388
|
|
|
$isUsingCdn && |
389
|
|
|
$location === self::ASSETS_SCRIPT_POSITION_HEADER && |
390
|
|
|
array_has($this->config, $configName . '.fallback')) { |
391
|
|
|
$scripts[] = $this->getFallbackScript($src, $configName); |
|
|
|
|
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
return $scripts; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* @return string |
399
|
|
|
*/ |
400
|
|
|
public function getBuildVersion() |
401
|
|
|
{ |
402
|
|
|
return $this->build = $this->config['enable_version'] ? '?v=' . $this->config['version'] : ''; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* @return HtmlBuilder |
407
|
|
|
*/ |
408
|
|
|
public function getHtmlBuilder() |
409
|
|
|
{ |
410
|
|
|
return $this->htmlBuilder; |
411
|
|
|
} |
412
|
|
|
} |
413
|
|
|
|
Let?s assume that you have the following
foreach
statement:$itemValue
is assigned by reference. This is possible because the expression (in the example$array
) can be used as a reference target.However, if we were to replace
$array
with something different like the result of a function call as inthen assigning by reference is not possible anymore as there is no target that could be modified.
Available Fixes
1. Do not assign by reference
2. Assign to a local variable first
3. Return a reference