Completed
Push — master ( 0824a2...27e52a )
by Sang
01:32
created

Assets::getFallbackScript()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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