Assets::addScripts()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Botble\Assets;
4
5
use Illuminate\Config\Repository;
6
use Illuminate\Support\Arr;
7
8
/**
9
 * Class Assets.
10
 *
11
 * @since 22/07/2015 11:23 PM
12
 */
13
class Assets
14
{
15
    /**
16
     * @var Repository
17
     */
18
    protected $config;
19
20
    /**
21
     * @var HtmlBuilder
22
     */
23
    protected $htmlBuilder;
24
25
    /**
26
     * @var array
27
     */
28
    protected $scripts = [];
29
30
    /**
31
     * @var array
32
     */
33
    protected $styles = [];
34
35
    /**
36
     * @var array
37
     */
38
    protected $appendedScripts = [
39
        'header' => [],
40
        'footer' => [],
41
    ];
42
43
    /**
44
     * @var array
45
     */
46
    protected $appendedStyles = [];
47
48
    /**
49
     * @var string
50
     */
51
    protected $build = '';
52
53
    const ASSETS_SCRIPT_POSITION_HEADER = 'header';
54
55
    const ASSETS_SCRIPT_POSITION_FOOTER = 'footer';
56
57
    /**
58
     * Assets constructor.
59
     *
60
     * @param Repository $config
61
     * @param HtmlBuilder $htmlBuilder
62
     */
63
    public function __construct(Repository $config, HtmlBuilder $htmlBuilder)
64
    {
65
        $this->config = $config->get('assets');
66
67
        $this->scripts = $this->config['scripts'];
68
69
        $this->styles = $this->config['styles'];
70
71
        $this->htmlBuilder = $htmlBuilder;
72
    }
73
74
    /**
75
     * Add scripts to current module.
76
     *
77
     * @param array $assets
78
     * @return $this
79
     */
80
    public function addScripts($assets)
81
    {
82
        $this->scripts = array_merge($this->scripts, (array)$assets);
83
84
        return $this;
85
    }
86
87
    /**
88
     * Add Css to current module.
89
     *
90
     * @param string[] $assets
91
     * @return $this
92
     */
93
    public function addStyles($assets)
94
    {
95
        $this->styles = array_merge($this->styles, (array)$assets);
96
97
        return $this;
98
    }
99
100
    /**
101
     * Add styles directly.
102
     *
103
     * @param array|string $assets
104
     * @return $this
105
     */
106
    public function addStylesDirectly($assets)
107
    {
108 View Code Duplication
        foreach ((array)$assets as &$item) {
0 ignored issues
show
Bug introduced by
The expression (array) $assets cannot be used as a reference.

Let?s assume that you have the following foreach statement:

foreach ($array as &$itemValue) { }

$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 in

foreach (getArray() as &$itemValue) { }

then assigning by reference is not possible anymore as there is no target that could be modified.

Available Fixes

1. Do not assign by reference
foreach (getArray() as $itemValue) { }
2. Assign to a local variable first
$array = getArray();
foreach ($array as &$itemValue) {}
3. Return a reference
function &getArray() { $array = array(); return $array; }

foreach (getArray() as &$itemValue) { }
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
            if (!in_array($item, $this->appendedStyles)) {
110
                $this->appendedStyles[$item] = [
111
                    'src'        => $item,
112
                    'attributes' => [],
113
                ];
114
            }
115
        }
116
117
        return $this;
118
    }
119
120
    /**
121
     * Add scripts directly.
122
     *
123
     * @param string|array $assets
124
     * @param string $location
125
     * @return $this
126
     */
127
    public function addScriptsDirectly($assets, $location = self::ASSETS_SCRIPT_POSITION_FOOTER)
128
    {
129 View Code Duplication
        foreach ((array)$assets as &$item) {
0 ignored issues
show
Bug introduced by
The expression (array) $assets cannot be used as a reference.

Let?s assume that you have the following foreach statement:

foreach ($array as &$itemValue) { }

$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 in

foreach (getArray() as &$itemValue) { }

then assigning by reference is not possible anymore as there is no target that could be modified.

Available Fixes

1. Do not assign by reference
foreach (getArray() as $itemValue) { }
2. Assign to a local variable first
$array = getArray();
foreach ($array as &$itemValue) {}
3. Return a reference
function &getArray() { $array = array(); return $array; }

foreach (getArray() as &$itemValue) { }
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
            if (!in_array($item, $this->appendedScripts[$location])) {
131
                $this->appendedScripts[$location][$item] = [
132
                    'src'        => $item,
133
                    'attributes' => [],
134
                ];
135
            }
136
        }
137
138
        return $this;
139
    }
140
141
    /**
142
     * Remove Css to current module.
143
     *
144
     * @param array $assets
145
     * @return $this
146
     */
147 View Code Duplication
    public function removeStyles($assets)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
    {
149
        if (empty($this->styles)) {
150
            return $this;
151
        }
152
153
        foreach ((array)$assets as $rem) {
154
            $index = array_search($rem, $this->styles);
155
            if ($index === false) {
156
                continue;
157
            }
158
159
            Arr::forget($this->styles, $index);
160
        }
161
162
        return $this;
163
    }
164
165
    /**
166
     * Add scripts.
167
     *
168
     * @param array $assets
169
     * @return $this
170
     */
171 View Code Duplication
    public function removeScripts($assets)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
    {
173
        if (empty($this->scripts)) {
174
            return $this;
175
        }
176
177
        foreach ((array)$assets as $rem) {
178
            $index = array_search($rem, $this->scripts);
179
            if ($index === false) {
180
                continue;
181
            }
182
183
            Arr::forget($this->scripts, $index);
184
        }
185
186
        return $this;
187
    }
188
189
    /**
190
     * Get All scripts in current module.
191
     *
192
     * @param string $location `header` or `footer`
193
     * @return array
194
     */
195
    public function getScripts($location = null)
196
    {
197
        $scripts = [];
198
199
        $this->scripts = array_unique($this->scripts);
200
201
        foreach ($this->scripts as $script) {
202
            $configName = 'resources.scripts.' . $script;
203
204
            if (!empty($location) && $location !== Arr::get($this->config, $configName . '.location')) {
205
                continue; // Skip assets that don't match this location
206
            }
207
208
            $scripts = array_merge($scripts, $this->getScriptItem($location, $configName, $script));
209
        }
210
211
        return array_merge($scripts, Arr::get($this->appendedScripts, $location, []));
212
    }
213
214
    /**
215
     * Get All CSS in current module.
216
     *
217
     * @param array $lastStyles Append last CSS to current module
218
     * @return array
219
     */
220
    public function getStyles($lastStyles = [])
221
    {
222
        $styles = [];
223
        if (!empty($lastStyles)) {
224
            $this->styles = array_merge($this->styles, $lastStyles);
225
        }
226
227
        $this->styles = array_unique($this->styles);
228
229
        foreach ($this->styles as $style) {
230
            $configName = 'resources.styles.' . $style;
231
232
            $styles = array_merge($styles, $this->getSource($configName));
233
        }
234
235
        return array_merge($styles, $this->appendedStyles);
236
    }
237
238
    /**
239
     * Convert script to html.
240
     *
241
     * @param string $name
242
     * @return  string|null
243
     */
244
    public function scriptToHtml($name)
245
    {
246
        return $this->itemToHtml($name, 'script');
247
    }
248
249
    /**
250
     * Convert style to html.
251
     *
252
     * @param string $name
253
     */
254
    public function styleToHtml($name)
255
    {
256
        return $this->itemToHtml($name, 'style');
257
    }
258
259
    /**
260
     * Get script item.
261
     *
262
     * @param string $location
263
     * @param string $configName
264
     * @param string $script
265
     * @return array
266
     */
267
    protected function getScriptItem($location, $configName, $script)
268
    {
269
        $scripts = $this->getSource($configName, $location);
270
271
        if (Arr::get($this->config, $configName . '.include_style')) {
272
            $this->addStyles([$script]);
273
        }
274
275
        return $scripts;
276
    }
277
278
    /**
279
     * Convert item to html.
280
     *
281
     * @param string $name
282
     * @param string $type
283
     * @return string
284
     */
285
    protected function itemToHtml($name, $type = 'style')
286
    {
287
        $html = '';
288
289
        if (!in_array($type, ['style', 'script'])) {
290
            return $html;
291
        }
292
293
        $configName = 'resources.' . $type . 's.' . $name;
294
295
        if (!Arr::has($this->config, $configName)) {
296
            return $html;
297
        }
298
299
        $src = $this->getSourceUrl($configName);
300
301
        foreach ((array)$src as $item) {
302
            $html .= $this->htmlBuilder->{$type}($item, ['class' => 'hidden'])->toHtml();
303
        }
304
305
        return $html;
306
    }
307
308
    /**
309
     * @param string $configName
310
     * @return string|array
311
     */
312
    protected function getSourceUrl($configName)
313
    {
314
        if (!Arr::has($this->config, $configName)) {
315
            return '';
316
        }
317
318
        $src = Arr::get($this->config, $configName . '.src.local');
319
320
        if ($this->isUsingCdn($configName)) {
321
            $src = Arr::get($this->config, $configName . '.src.cdn');
322
        }
323
324
        return $src;
325
    }
326
327
    /**
328
     * @param string $configName
329
     * @return bool
330
     */
331
    protected function isUsingCdn($configName)
332
    {
333
        return Arr::get($this->config, $configName . '.use_cdn', false) && !$this->config['offline'];
334
    }
335
336
    /**
337
     * @param string $configName
338
     * @param string $location
339
     * @return array
340
     */
341
    protected function getSource($configName, $location = null)
342
    {
343
        $isUsingCdn = $this->isUsingCdn($configName);
344
345
        $attributes = $isUsingCdn ? [] : Arr::get($this->config, $configName . '.attributes', []);
346
347
        $src = $this->getSourceUrl($configName);
348
349
        $scripts = [];
350
351
        foreach ((array)$src as $s) {
352
            $scripts[] = [
353
                'src'        => $s,
354
                'attributes' => $attributes,
355
            ];
356
        }
357
358
        if (empty($src) &&
359
            $isUsingCdn &&
360
            $location === self::ASSETS_SCRIPT_POSITION_HEADER &&
361
            Arr::has($this->config, $configName . '.fallback')) {
362
            $scripts[] = [
363
                'src'         => $src,
364
                'fallback'    => Arr::get($this->config, $configName . '.fallback'),
365
                'fallbackURL' => Arr::get($this->config, $configName . '.src.local'),
366
            ];
367
        }
368
369
        return $scripts;
370
    }
371
372
    /**
373
     * @return string
374
     */
375
    public function getBuildVersion()
376
    {
377
        return $this->build = $this->config['enable_version'] ? '?v=' . $this->config['version'] : '';
378
    }
379
380
    /**
381
     * @return HtmlBuilder
382
     */
383
    public function getHtmlBuilder()
384
    {
385
        return $this->htmlBuilder;
386
    }
387
388
    /**
389
     * Render assets to header.
390
     *
391
     * @param array $lastStyles
392
     * @return string
393
     * @throws \Throwable
394
     */
395
    public function renderHeader($lastStyles = [])
396
    {
397
        $styles = $this->getStyles($lastStyles);
398
399
        $headScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_HEADER);
400
401
        return view('assets::header', compact('styles', 'headScripts'))->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\Contracts\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
402
    }
403
404
    /**
405
     * Render assets to footer.
406
     *
407
     * @return string
408
     * @throws \Throwable
409
     */
410
    public function renderFooter()
411
    {
412
        $bodyScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_FOOTER);
413
414
        return view('assets::footer', compact('bodyScripts'))->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\Contracts\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
415
    }
416
}
417