Completed
Push — master ( cbeb2a...13c174 )
by Sang
06:50
created

Assets::addStyles()   A

Complexity

Conditions 2
Paths 2

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