Completed
Push — master ( e8aa75...cbeb2a )
by Sang
36:33
created

Assets::addStylesheetsDirectly()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16

Duplication

Lines 13
Ratio 81.25 %

Importance

Changes 0
Metric Value
dl 13
loc 16
rs 9.7333
c 0
b 0
f 0
cc 4
nc 6
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 $javascript = [];
30
31
    /**
32
     * @var array
33
     */
34
    protected $stylesheets = [];
35
36
    /**
37
     * @var string
38
     */
39
    protected $build = '';
40
41
    /**
42
     * @var array
43
     */
44
    protected $appendedJs = [
45
        'top'    => [],
46
        'bottom' => [],
47
    ];
48
49
    /**
50
     * @var array
51
     */
52
    protected $appendedCss = [];
53
54
    /**
55
     * Assets constructor.
56
     * @author Sang Nguyen
57
     * @param Repository $config
58
     * @param HtmlBuilder $htmlBuilder
59
     */
60
    public function __construct(Repository $config, HtmlBuilder $htmlBuilder)
61
    {
62
        $this->config = $config;
63
        $this->htmlBuilder = $htmlBuilder;
64
65
        $this->javascript = $this->config->get('assets.javascript');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->config->get('assets.javascript') of type * is incompatible with the declared type array of property $javascript.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
66
        $this->stylesheets = $this->config->get('assets.stylesheets');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->config->get('assets.stylesheets') of type * is incompatible with the declared type array of property $stylesheets.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
67
68
        $this->build = $this->config->get('assets.enable_version') ? '?v=' . $this->config->get('assets.version') : '';
69
    }
70
71
    /**
72
     * Add Javascript to current module
73
     *
74
     * @param array $assets
75
     * @return $this
76
     * @author Sang Nguyen
77
     */
78
    public function addJavascript($assets)
79
    {
80
        if (!is_array($assets)) {
81
            $assets = [$assets];
82
        }
83
        $this->javascript = array_merge($this->javascript, $assets);
84
        return $this;
85
    }
86
87
    /**
88
     * Add Css to current module
89
     *
90
     * @param array $assets
91
     * @return $this
92
     * @author Sang Nguyen
93
     */
94
    public function addStylesheets($assets)
95
    {
96
        if (!is_array($assets)) {
97
            $assets = [$assets];
98
        }
99
        $this->stylesheets = array_merge($this->stylesheets, $assets);
100
        return $this;
101
    }
102
103
    /**
104
     * @param $assets
105
     * @return $this
106
     * @author Sang Nguyen
107
     */
108 View Code Duplication
    public function addStylesheetsDirectly($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...
109
    {
110
        if (!is_array($assets)) {
111
            $assets = func_get_args();
112
        }
113
        foreach ($assets as &$item) {
114
            $item = $item . $this->build;
115
            if (!in_array($item, $this->appendedCss)) {
116
                $this->appendedCss[] = [
117
                    'src' => $item,
118
                    'attributes' => [],
119
                ];
120
            }
121
        }
122
        return $this;
123
    }
124
125
    /**
126
     * @param $assets
127
     * @param string $location
128
     * @return $this
129
     * @author Sang Nguyen
130
     */
131 View Code Duplication
    public function addJavascriptDirectly($assets, $location = 'bottom')
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...
132
    {
133
        if (!is_array($assets)) {
134
            $assets = func_get_args();
135
        }
136
137
        foreach ($assets as &$item) {
138
            $item = $item . $this->build;
139
            if (!in_array($item, $this->appendedJs[$location])) {
140
                $this->appendedJs[$location][] = ['src' => $item, 'attributes' => []];
141
            }
142
        }
143
        return $this;
144
    }
145
146
    /**
147
     * Remove Css to current module
148
     *
149
     * @param array $assets
150
     * @return $this
151
     * @author Sang Nguyen
152
     */
153 View Code Duplication
    public function removeStylesheets($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...
154
    {
155
        if (!is_array($assets)) {
156
            $assets = [$assets];
157
        }
158
        foreach ($assets as $rem) {
159
            unset($this->stylesheets[array_search($rem, $this->stylesheets)]);
160
        }
161
        return $this;
162
    }
163
164
    /**
165
     * Add Javascript to current module
166
     *
167
     * @param array $assets
168
     * @return $this
169
     * @author Sang Nguyen
170
     */
171 View Code Duplication
    public function removeJavascript($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 (!is_array($assets)) {
174
            $assets = [$assets];
175
        }
176
        foreach ($assets as $rem) {
177
            unset($this->javascript[array_search($rem, $this->javascript)]);
178
        }
179
        return $this;
180
    }
181
182
    /**
183
     * Get All Javascript in current module
184
     *
185
     * @param string $location : top or bottom
186
     * @param boolean $version : show version?
187
     * @return array
188
     * @author Sang Nguyen
189
     */
190
    public function getJavascript($location = null, $version = true)
191
    {
192
        $scripts = [];
193
        $this->javascript = array_unique($this->javascript);
194
        foreach ($this->javascript as $script) {
195
            $configName = 'assets.resources.javascript.' . $script;
196
197
            if ($this->config->has($configName)) {
198
                if (!empty($location) && $location != $this->config->get($configName . '.location')) {
199
                    continue; // Skip assets that don't match this location
200
                }
201
202
                $src = $this->config->get($configName . '.src.local');
203
                $cdn = false;
204
                $attributes = $this->config->get($configName . '.attributes', []);
205 View Code Duplication
                if ($this->config->get($configName . '.use_cdn') && !$this->config->get('assets.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...
206
                    $src = $this->config->get($configName . '.src.cdn');
207
                    $cdn = true;
208
                    $attributes = [];
209
                }
210
211
                if ($this->config->get($configName . '.include_style')) {
212
                    $this->addStylesheets([$script]);
213
                }
214
215
                $version = $version ? $this->build : '';
216
                if (!is_array($src)) {
217
                    $scripts[] = ['src' => $src . $version, 'attributes' => $attributes];
218
                } else {
219
                    foreach ($src as $s) {
220
                        $scripts[] = ['src' => $s . $version, 'attributes' => $attributes];
221
                    }
222
                }
223
224
                if (empty($src) && $cdn && $location === 'top' && $this->config->has($configName . '.fallback')) {
225
                    // Fallback to local script if CDN fails
226
                    $fallback = $this->config->get($configName . '.fallback');
227
                    $scripts[] = [
228
                        'src'         => $src,
229
                        'fallback'    => $fallback,
230
                        'fallbackURL' => $this->config->get($configName . '.src.local'),
231
                    ];
232
                }
233
            }
234
        }
235
236
        if (isset($this->appendedJs[$location])) {
237
            $scripts = array_merge($scripts, $this->appendedJs[$location]);
238
        }
239
240
        return $scripts;
241
    }
242
243
    /**
244
     * Get All CSS in current module
245
     *
246
     * @param array $lastModules : append last CSS to current module
247
     * @param boolean $version : show version?
248
     * @return array
249
     * @author Sang Nguyen
250
     */
251
    public function getStylesheets($lastModules = [], $version = true)
252
    {
253
        $stylesheets = [];
254
        if (!empty($lastModules)) {
255
            $this->stylesheets = array_merge($this->stylesheets, $lastModules);
256
        }
257
258
        $this->stylesheets = array_unique($this->stylesheets);
259
        foreach ($this->stylesheets as $style) {
260
            $configName = 'assets.resources.stylesheets.' . $style;
261
            if ($this->config->has($configName)) {
262
                $src = $this->config->get($configName . '.src.local');
263
                $attributes = $this->config->get($configName . '.attributes', []);
264 View Code Duplication
                if ($this->config->get($configName . '.use_cdn') && !$this->config->get('assets.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...
265
                    $src = $this->config->get($configName . '.src.cdn');
266
                    $attributes = [];
267
                }
268
269
                foreach ((array)$src as $s) {
270
                    $stylesheets[] = [
271
                        'src'        => $s . ($version ? $this->build : ''),
272
                        'attributes' => $attributes,
273
                    ];
274
                }
275
            }
276
        }
277
278
        return array_merge($stylesheets, $this->appendedCss);
279
    }
280
281
    /**
282
     * @param $name
283
     * @param bool $version
284
     * @author Sang Nguyen
285
     */
286
    public function javascriptToHtml($name, $version = true)
287
    {
288
        return $this->itemToHtml($name, $version, 'script');
289
    }
290
291
    /**
292
     * @param $name
293
     * @param bool $version
294
     * @author Sang Nguyen
295
     */
296
    public function stylesheetToHtml($name, $version = true)
297
    {
298
        return $this->itemToHtml($name, $version, 'style');
299
    }
300
301
    /**
302
     * @param $name
303
     * @param bool $version
304
     * @param string $type
305
     * @return null|string
306
     */
307
    protected function itemToHtml($name, $version = true, $type = 'style')
308
    {
309
        if (!in_array($type, ['style', 'script'])) {
310
            return null;
311
        }
312
313
        $config = 'assets.resources.stylesheets.' . $name;
314
        if ($type === 'script') {
315
            $config = 'assets.resources.javascript.' . $name;
316
        }
317
318
        if ($this->config->has($config)) {
319
320
            $src = $this->config->get($config . '.src.local');
321
            if ($this->config->get($config . '.use_cdn') && !$this->config->get('assets.offline')) {
322
                $src = $this->config->get($config . '.src.cdn');
323
            }
324
325
            if (!is_array($src)) {
326
                $src = [$src];
327
            }
328
329
            $html = '';
330
            foreach ($src as $item) {
331
                $html .= $this->htmlBuilder->{$type}($item . ($version ? $this->build : ''), ['class' => 'hidden'])->toHtml();
332
            }
333
334
            return $html;
335
        }
336
337
        return null;
338
    }
339
340
    /**
341
     * @return string
342
     * @throws \Throwable
343
     * @author Sang Nguyen
344
     */
345
    public function renderHeader()
346
    {
347
        $stylesheets = $this->getStylesheets(['core']);
348
        $headScripts = $this->getJavascript('top');
349
        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...
350
    }
351
352
    /**
353
     * @return string
354
     * @throws \Throwable
355
     * @author Sang Nguyen
356
     */
357
    public function renderFooter()
358
    {
359
        $bodyScripts = $this->getJavascript('bottom');
360
        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...
361
    }
362
}
363