GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 5b2683...2f55d1 )
by Miles
22:07
created

Vars   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 435
Duplicated Lines 3.68 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 54
c 2
b 0
f 1
lcom 1
cbo 4
dl 16
loc 435
rs 7.0642

19 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 29 4
A makeCache() 0 5 1
A makePaths() 0 9 3
C makeLoaders() 0 47 12
A makeVariables() 0 14 3
A loadFromCache() 0 23 3
A makeExtensions() 0 14 3
B pathsLoadedCheck() 0 18 5
A getLoaders() 0 4 1
A getExtensions() 0 4 1
A getBasePath() 0 4 1
A setBasePath() 16 16 3
A addResource() 0 7 1
A updateResource() 0 5 1
B resourceImported() 0 11 6
A getResource() 0 10 3
A getResources() 0 4 1
A getVariables() 0 4 1
A getCache() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Vars often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Vars, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the m1\vars library
5
 *
6
 * (c) m1 <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @package     m1/vars
12
 * @version     0.1.0
13
 * @author      Miles Croxford <[email protected]>
14
 * @copyright   Copyright (c) Miles Croxford <[email protected]>
15
 * @license     http://github.com/m1/vars/blob/master/LICENSE
16
 * @link        http://github.com/m1/vars/blob/master/README.MD Documentation
17
 */
18
19
namespace M1\Vars;
20
21
use M1\Vars\Cache\CacheProvider;
22
use M1\Vars\Resource\AbstractResource;
23
use M1\Vars\Resource\ResourceProvider;
24
use M1\Vars\Resource\VariableResource;
25
26
/**
27
 * Vars core class
28
 *
29
 * @since 0.1.0
30
 */
31
class Vars extends AbstractResource
32
{
33
    /**
34
     * The base path for the Vars config and cache folders
35
     *
36
     * @var string $base_path
37
     */
38
    private $base_path;
39
40
    /**
41
     * The cache object if the cache is wanted, else false
42
     *
43
     * @var \M1\Vars\Cache\CacheProvider $cache
44
     */
45
    public $cache;
46
47
    /**
48
     * The available extensions
49
     *
50
     * @var array $extensions
51
     */
52
    private $extensions = array();
53
54
    /**
55
     * The default options for Vars
56
     *
57
     * @var array $default_options
58
     */
59
    private $default_options = array(
60
        'base_path' => null,
61
        'cache' => true,
62
        'cache_path' => null,
63
        'cache_expire' => 300, // 5 minutes
64
        'loaders' => array('ini', 'json', 'php', 'toml', 'yaml', 'xml',)
65
    );
66
67
    /**
68
     * The available loaders
69
     *
70
     * @var array $loaders
71
     */
72
    private $loaders = array();
73
74
    /**
75
     * Have the base and cache paths been set
76
     *
77
     * @var bool $paths_loaded
78
     */
79
    private $paths_loaded = false;
80
81
    /**
82
     * The imported resources
83
     *
84
     * @var array $resources
85
     */
86
    private $resources = array();
87
88
    /**
89
     * The words to be replaced in the config files
90
     *
91
     * @var array $variables
92
     */
93
    private $variables = array();
94
95
    /**
96
     * Creates a new instance of Vars
97
     *
98
     * @param string|array $resource The main configuration resource
99
     * @param array        $options  The options being used for Vars
100
     */
101
    public function __construct($resource, $options = null)
102
    {
103
        if (!$options) {
104
            $options = $this->default_options;
105
        } else {
106
            $options = array_merge($this->default_options, $options);
107
        }
108
109
        $this->makeCache($options, $resource);
110
        $this->makePaths($options);
111
112
        if (!$this->cache->checkCache()) {
113
            $this->makeLoaders($options);
114
            $this->makeVariables($options);
115
116
            $resource = new ResourceProvider($this, $resource);
117
        }
118
119
        if ($this->cache->isHit()) {
120
            $this->loadFromCache();
121
        } else {
122
            $resource->mergeParentContent();
0 ignored issues
show
Bug introduced by
It seems like $resource is not always an object, but can also be of type string|array. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
123
            $this->content = $resource->getContent();
124
125
            $this->cache->setTime(time());
126
            $this->cache->makeCache($this);
127
128
        }
129
    }
130
131
    /**
132
     * Makes the CacheProvider with the options
133
     *
134
     * @param array        $options  The options being used for Vars
135
     * @param array|string $resource The main configuration resource
136
     */
137
    private function makeCache($options, $resource)
138
    {
139
        $cache = new CacheProvider($resource, array_merge($this->default_options, $options));
140
        $this->cache = $cache;
141
    }
142
143
    /**
144
     * Sets the base path if the options have been set and the cache path if the cache path has not been set but the
145
     * base path has
146
     *
147
     * @param array $options The options being used for Vars
148
     */
149
    private function makePaths($options)
150
    {
151
        $this->setBasePath($options['base_path']);
152
153
        if (is_null($options['cache_path']) && !is_null($options['base_path'])) {
154
            $this->cache->setPath($options['base_path']);
155
            $this->paths_loaded = true;
156
        }
157
    }
158
159
    /**
160
     * Get loaders and make extensions for the loaders
161
     *
162
     * @param array|null $options The options being used for Vars
163
     *
164
     * @throws \InvalidArgumentException If a loader from options isn't found
165
     * @throws \InvalidArgumentException If no loaders were loaded
166
     */
167
    private function makeLoaders($options)
168
    {
169
        $loaders = array();
170
        $default_loaders = $this->default_options['loaders'];
171
172
        if (isset($options['loaders']) && !is_null($options['loaders']) && !empty($options['loaders'])) {
173
            if (is_array($options['loaders'])) {
174
                $loaders = $options['loaders'];
175
            } elseif (is_string($options['loaders'])) {
176
                $loaders[] = $options['loaders'];
177
            }
178
        } else {
179
            $loaders = $default_loaders;
180
        }
181
182
        $parsed_loaders = array();
183
184
        foreach ($loaders as $loader) {
185
            if ($loader === 'default') {
186
                $parsed_loaders = array_merge($parsed_loaders, $default_loaders);
187
            } else {
188
                $parsed_loaders[] = $loader;
189
            }
190
        }
191
192
        $parsed_loaders = array_unique($parsed_loaders);
193
        $namespaced_loaders = array();
194
195
        foreach ($parsed_loaders as $loader) {
196
            if (in_array($loader, $default_loaders)) {
197
                $loader = sprintf('%s\Loader\%sLoader', __NAMESPACE__, ucfirst(strtolower($loader)));
198
            }
199
200
            if (!class_exists($loader)) {
201
                throw new \InvalidArgumentException(sprintf("'%s' loader class does not exist", $loader));
202
            }
203
204
            $namespaced_loaders[] = $loader;
205
        }
206
207
        if (!$namespaced_loaders) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespaced_loaders of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
208
            throw new \InvalidArgumentException('No loaders were loaded');
209
        }
210
211
        $this->loaders = $namespaced_loaders;
212
        $this->extensions = $this->makeExtensions($namespaced_loaders);
213
    }
214
215
    /**
216
     * Sets the replacement variables if the option has been set
217
     *
218
     * @param array|null $options The options being used for Vars
219
     */
220
    private function makeVariables($options)
221
    {
222
        if (isset($options['variables'])) {
223
            $variables = new VariableResource($this, $options['variables']);
224
225
            $v = array();
226
227
            foreach ($variables->getVariables() as $variable_key => $variable_value) {
228
                $v["%".$variable_key.'%'] = $variable_value;
229
            }
230
231
            $this->variables = $v;
232
        }
233
    }
234
235
    /**
236
     * Loads the cached file into the current class
237
     */
238
    private function loadFromCache()
239
    {
240
        $this->cache->load();
241
242
        $passed_keys = array(
243
            'base_path',
244
            'content',
245
            'extensions',
246
            'loaders',
247
            'resources',
248
            'variables',
249
        );
250
251
        $loaded_vars = get_object_vars($this->cache->getLoadedVars());
252
253
        foreach ($loaded_vars as $key => $value) {
254
            if (in_array($key, $passed_keys)) {
255
                $this->$key = $value;
256
            }
257
        }
258
259
        $this->cache->setTime($loaded_vars['cache']->getTime());
260
    }
261
262
    /**
263
     * Get and make extensions for loaders made from makeLoaders()
264
     *
265
     * @see \M1\Vars\Vars::makeLoaders() \M1\Vars\Vars::makeLoaders()
266
     *
267
     * @param  array $loaders File loaders
268
     *
269
     * @throws \RuntimeException If no loader extensions were found
270
     *
271
     * @return array File loader supported extensions
272
     */
273
    private function makeExtensions(array $loaders)
274
    {
275
        $extensions = array();
276
277
        foreach ($loaders as $loader) {
278
            $extensions = array_merge($extensions, $loader::$supported);
279
        }
280
281
        if (!$extensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extensions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
282
            throw new \RuntimeException('No loader extensions were found');
283
        }
284
285
        return $extensions;
286
    }
287
288
    /**
289
     * Checks if the base and cache paths have been set, if not set then will use the $resource as the base path
290
     *
291
     * @param string $resource The resource to use to set the paths if they haven't been set
292
     */
293
    public function pathsLoadedCheck($resource)
294
    {
295
        if (!$this->paths_loaded) {
296
            $base_path = $this->getBasePath();
297
298
            if (!$base_path) {
299
                $file = pathinfo(realpath($resource));
300
                $base_path = $file['dirname'];
301
                $this->setBasePath($base_path);
302
            }
303
304
            if ($this->cache->getProvide() && !$this->cache->getPath()) {
305
                $this->cache->setPath($base_path);
306
            }
307
308
            $this->paths_loaded = true;
309
        }
310
    }
311
312
    /**
313
     * Get the Vars file loaders
314
     *
315
     * @return array The Vars file loaders
316
     */
317
    public function getLoaders()
318
    {
319
        return $this->loaders;
320
    }
321
322
    /**
323
     * Get the Vars file loaders extensions
324
     *
325
     * @return array The Vars file loader extensions
326
     */
327
    public function getExtensions()
328
    {
329
        return $this->extensions;
330
    }
331
332
    /**
333
     * Get the Vars base path
334
     *
335
     * @return string The Vars base path
336
     */
337
    public function getBasePath()
338
    {
339
        return $this->base_path;
340
    }
341
342
    /**
343
     * Set the Vars base path
344
     *
345
     * @param string $base_path The base path to set
346
     *
347
     * @throws \InvalidArgumentException If the base path does not exist or is not writable
348
     *
349
     * @return \M1\Vars\Vars
350
     */
351 View Code Duplication
    public function setBasePath($base_path)
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...
352
    {
353
        if (is_null($base_path)) {
354
            return;
355
        }
356
357
        if (!is_dir($base_path)) {
358
            throw new \InvalidArgumentException(sprintf(
359
                "'%s' base path does not exist or is not writable",
360
                $base_path
361
            ));
362
        }
363
364
        $this->base_path = realpath($base_path);
365
        return $this;
366
    }
367
368
369
370
    /**
371
     * Adds a resource to $this->resources
372
     *
373
     * @param string $resource Resource to add to the stack
374
     *
375
     * @return int The position of the added resource
376
     */
377
    public function addResource($resource)
378
    {
379
        $r = realpath($resource);
380
        $pos = count($this->resources);
381
        $this->resources[$pos] = $r;
382
        return $pos;
383
    }
384
385
    /**
386
     * Updates the string resource with the FileResource
387
     *
388
     * @param \M1\Vars\Resource\FileResource $resource The FileResource to add
389
     * @param int                            $pos      The position of the string resource
390
     *
391
     * @return \M1\Vars\Vars
392
     */
393
    public function updateResource($resource, $pos)
394
    {
395
        $this->resources[$pos] = $resource;
396
        return $this;
397
    }
398
399
    /**
400
     * Tests to see if the resource has been imported already -- this is to avoid getting into a infinite loop
401
     *
402
     * @param \M1\Vars\Resource\FileResource|string $resource Resource to check
403
     *
404
     * @return bool Has resource already been imported
405
     */
406
    public function resourceImported($resource)
407
    {
408
        $resource = realpath($resource);
409
        foreach ($this->getResources() as $r) {
410
            if ((is_a($r, 'M1\Vars\Resource\FileResource') && $resource === $r->getFile()) ||
411
                (is_string($r) && $resource === $r)) {
412
                return true;
413
            }
414
        }
415
        return false;
416
    }
417
418
    /**
419
     * Searches the resource stack for a certain resource
420
     *
421
     * @param string $resource The resource to search for
422
     *
423
     * @return bool Returns the resource if found
424
     */
425
    public function getResource($resource)
426
    {
427
        foreach ($this->getResources() as $r) {
428
            if ($resource === $r->getFilename()) {
429
                return $r;
430
            }
431
        }
432
433
        return false;
434
    }
435
436
    /**
437
     * Returns the imported resources
438
     *
439
     * @return array The Vars imported resources
440
     */
441
    public function getResources()
442
    {
443
        return $this->resources;
444
    }
445
446
    /**
447
     * Returns the Vars replacement variables
448
     *
449
     * @return array The Vars replacement variables
450
     */
451
    public function getVariables()
452
    {
453
        return $this->variables;
454
    }
455
456
    /**
457
     * Returns the CacheProvider if set, if not return false
458
     *
459
     * @return \M1\Vars\Cache\CacheProvider|false The CacheProvider or false
460
     */
461
    public function getCache()
462
    {
463
        return $this->cache;
464
    }
465
}
466