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 ( 3ea8d5...bca756 )
by Miles
02:17
created

FileResource::getBooleanValue()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.2
cc 4
eloc 5
nc 2
nop 1
crap 4
1
<?php
2
3
/**
4
 * This file is part of the m1\vars library
5
 *
6
 * Copyright (c) Miles Croxford <[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.3.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\Resource;
20
21
use M1\Vars\Traits\FileTrait;
22
use M1\Vars\Traits\ResourceFlagsTrait;
23
use Symfony\Component\Filesystem\Filesystem;
24
25
/**
26
 * File Resource enables interaction with files as resources
27
 *
28
 * @since 0.1.0
29
 */
30
class FileResource extends AbstractResource
31
{
32
    /**
33
     * Basic file interaction logic
34
     */
35
    use FileTrait;
36
37
    use ResourceFlagsTrait;
38
39
    /**
40
     * The env separator for environment replacements
41
     *
42
     * @var string
43
     */
44
    private static $env_separator = '_ENV::';
45
46
    /**
47
     * The filename of the loaded file
48
     *
49
     * @var string
50
     */
51
    private $filename;
52
53
    /**
54
     * The parent ResourceProvider
55
     *
56
     * @var \M1\Vars\Resource\ResourceProvider
57
     */
58
    private $provider;
59
60
    /**
61
     * The raw content from the passed file
62
     *
63
     * @var mixed
64
     */
65
    private $raw_content = array();
66
67
    /**
68
     * The file resource constructor to get and parse the content from files
69
     *
70
     * @param \M1\Vars\Resource\ResourceProvider $provider The parent ResourceProvider
71
     * @param string                             $file     The passed file
72
     */
73 69
    public function __construct(ResourceProvider $provider, $file)
74
    {
75 69
        $this->provider = $provider;
76 69
        $this->vars = $provider->vars;
77
78 69
        $this->makePaths($file);
79 69
        $this->validate();
80
81 69
        $content = $this->loadContent($this->file);
82 62
        $this->raw_content = $content;
83
84 62
        if ($content) {
85 58
            $this->content = $this->searchForResources($content);
86 56
        }
87 60
    }
88
89
    /**
90
     * Make the paths used for the filename variable
91
     *
92
     * @param string $file The passed file
93
     */
94 69
    private function makePaths($file)
95
    {
96 69
        $file = realpath($file);
97
98 69
        $base_path = $this->provider->vars->getBasePath();
99
100 69
        $filesystem = new Filesystem();
101 69
        $abs_path = $filesystem->makePathRelative(
102 69
            $file,
103
            $base_path
104 69
        );
105
106 69
        $this->file = $file;
107 69
        $this->filename = rtrim($abs_path, "/");
108 69
    }
109
110
    /**
111
     * Search for imports in the files and does the replacement variables
112
     *
113
     * @param mixed $content The file content received from the loader
114
     *
115
     * @return array Returns the parsed content
116
     */
117 58
    private function searchForResources($content = array())
118
    {
119 58
        $returned_content = array();
120
121 58
        foreach ($content as $ck => $cv) {
122 58
            $returned_content = $this->parseContent($ck, $cv, $returned_content);
123 56
        }
124
125 56
        return $returned_content;
126
    }
127
128
    /**
129
     * Parses the contents inside the content array
130
     *
131
     * @param mixed $key              The key of the content array
132
     * @param mixed $value            The value of the key
133
     * @param array $returned_content The modified content array to return
134
     *
135
     * @return array Returns the modified content array
136
     */
137 58
    private function parseContent($key, $value, $returned_content)
138
    {
139 58
        if ($key === 'imports' && !is_null($value) && !empty($value)) {
140 49
            $imported_resource = $this->useImports($value);
141
142 47
            if ($imported_resource) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $imported_resource 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...
143 44
                $returned_content = array_replace_recursive($returned_content, $imported_resource);
144 44
            }
145
146 56
        } elseif (is_array($value)) {
147 11
            $returned_content[$key] = $this->searchForResources($value);
148 11
        } else {
149 53
            $returned_content[$key] = $this->parseText($value);
150
        }
151
152 56
        return $returned_content;
153
    }
154
    /**
155
     * Parses the text for option and environment replacements and replaces the text
156
     *
157
     * @param string $text The text to be parsed
158
     *
159
     * @return string|null The parsed string
160
     */
161 53
    private function parseText($text)
162
    {
163 53
        if (substr($text, 0, 6) === self::$env_separator) {
164 1
            $variable = trim(substr($text, strlen(self::$env_separator)));
165
166 1
            if ($variable) {
167 1
                $value = getenv($variable);
168
169 1
                if ($value) {
170 1
                    return $value;
171
                }
172 1
            }
173 1
        } else {
174 52
            return strtr($text, $this->vars->getVariables());
175
        }
176
177 1
        return null;
178
    }
179
180
    /**
181
     * Use the import arrays to import resources
182
     *
183
     * @param mixed $imports The resources wanting to be imported
184
     *
185
     * @return array The parsed imported resources
186
     */
187 49
    private function useImports($imports)
188
    {
189 49
        $imported_resources = array();
190
191 49
        if ((is_array($imports) && $this->isAssoc($imports)) || is_string($imports)) {
192 43
            $imports = array($imports);
193 43
        }
194
195 49
        foreach ($imports as $import) {
0 ignored issues
show
Bug introduced by
The expression $imports of type object|integer|double|null|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
196 49
            $imported_resources = $this->processImport($import, $imported_resources);
197 47
        }
198
199 47
        return $imported_resources;
200
    }
201
202
    /**
203
     * Processes the import and gets individual import if set and passes them off to import2Resources()
204
     *
205
     * @param mixed $import The import to be processed
206
     * @param array $imported_resources The array of imported resources
207
     *
208
     * @return array The parsed imported resources
209
     */
210 49
    private function processImport($import, array $imported_resources)
211
    {
212 49
        if (is_array($import) && array_key_exists('resource', $import) && is_array($import['resource'])) {
213 1
            foreach ($import['resource'] as $resource) {
214
                $temp = array(
215 1
                    'resource' => $resource,
216 1
                    'relative' => $this->checkBooleanValue('relative', $import),
217 1
                    'recursive' => $this->checkBooleanValue('recursive', $import),
218 1
                );
219
220 1
                $imported_resources = $this->import2Resource($temp, $imported_resources);
221 1
            }
222 1
        } else {
223 49
            $imported_resources = $this->import2Resource($import, $imported_resources);
224
        }
225
226 47
        return $imported_resources;
227
    }
228
229
    /**
230
     * Creates the resource from the import then imports it
231
     *
232
     * @param array|string $import The string|array to be converted to a resource
233
     * @param array $imported_resources The array of imported resources
234
     *
235
     * @return array The imported resources
236
     */
237 49
    private function import2Resource($import, array $imported_resources)
238
    {
239 49
        $resource = $this->createResource($import);
240
241 47
        if ($resource) {
242 47
            $imported_resources = $this->importResource($resource, $imported_resources);
243 47
        }
244
245 47
        return $imported_resources;
246
    }
247
248
    /**
249
     * Creates resource from the import
250
     *
251
     * @param array|string $import The import to create a resource from
252
     *
253
     * @return array|\M1\Vars\Resource\ResourceProvider The resource of the import
254
     */
255 49
    private function createResource($import)
256
    {
257 49
        if (is_array($import) && array_key_exists('resource', $import)) {
258 10
            $import_resource = $import;
259 10
            $import_resource['relative'] = $this->checkBooleanValue('relative', $import_resource);
260 10
            $import_resource['recursive'] = $this->checkBooleanValue('recursive', $import_resource);
261
262 49
        } elseif (is_string($import)) {
263 40
            $import_resource = array('resource' => $import, 'relative' => true, 'recursive' => true);
264 40
        }
265
266 49
        $import_resource = new ResourceProvider(
267 49
            $this->provider->vars,
268 49
            $this->createImportName($import_resource['resource']),
0 ignored issues
show
Bug introduced by
The variable $import_resource does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
It seems like $import_resource['resource'] can also be of type boolean; however, M1\Vars\Resource\FileResource::createImportName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
269 49
            $import_resource['relative'],
0 ignored issues
show
Bug introduced by
It seems like $import_resource['relative'] can also be of type string; however, M1\Vars\Resource\ResourceProvider::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
270 49
            $import_resource['recursive']
0 ignored issues
show
Bug introduced by
It seems like $import_resource['recursive'] can also be of type string; however, M1\Vars\Resource\ResourceProvider::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
271 49
        );
272
273 47
        return $import_resource;
274
    }
275
276
    /**
277
     * Creates the correctly formatted resource name with paths
278
     *
279
     * @param string $resource The resource to create the import name for
280
     *
281
     * @return string The parsed resource
282
     */
283 49
    private function createImportName($resource)
284
    {
285 49
        $resource = $this->explodeResourceIfElse($resource);
286 49
        $resource_pieces = array();
287
        
288 49
        foreach ($resource as $r) {
289
            //$suppress = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
290
            //$recursive = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
291
            //
292
            ////if ($this->checkSuppression($r)) {
293
            ////    $suppress = true;
294
            ////    $r = trim($r, "@");
295
            ////}
296
            ////
297
            ////if ($this->checkRecursive($r)) {
298
            ////    $recursive = true;
299
            ////    $r = trim($r, "*");
300
            ////}
301
            ////
302
            ////$r = $this->removeFlags($r);
303
304 49
            $parsed_r = $this->trimFlags($r);
305 49
            $parsed_r = sprintf('%s/%s', dirname($this->file), $parsed_r);
306 49
            $parsed_r = $this->replicateFlags($parsed_r, $r);
307
308 49
            $resource_pieces[] = $parsed_r;
309 49
        }
310
311 49
        return $this->implodeResourceIfElse($resource_pieces);
312
313
    }
314
315
    /**
316
     * Import resource into the imported resources and merge contents
317
     *
318
     * @param ResourceProvider $provider The new imported resource
319
     * @param array            $imported_resources The imported resources
320
     *
321
     * @return array The modified imported resources
322
     */
323 47
    private function importResource(ResourceProvider $provider, $imported_resources)
324
    {
325 47
        $content = $provider->getContent();
326 47
        $parent_content = $provider->getParentContent();
327
328 47
        if (!empty($content)) {
329 44
            $imported_resources = array_replace_recursive($imported_resources, $content);
330 44
        }
331
332 47
        if (!empty($parent_content)) {
333 7
            $this->provider->addParentContent($parent_content);
334 7
        }
335
336 47
        return $imported_resources;
337
    }
338
339
    /**
340
     * Returns whether the passed array is associative
341
     *
342
     * @param array $array The passed array
343
     *
344
     * @return bool Is the passed array associative
345
     */
346 11
    private function isAssoc(array $array)
347
    {
348 11
        return array_keys($array) !== range(0, count($array) - 1);
349
    }
350
351
    /**
352
     * Checks if the passed boolean value is true or false
353
     *
354
     * @param string $value  The value to check
355
     * @param mixed  $import The passed import
356
     *
357
     * @return bool Returns the value of the boolean
358
     */
359 10
    public function checkBooleanValue($value, $import)
360
    {
361 10
        $default = false;
362
363 10
        if ($value === 'relative') {
364 10
            $default = true;
365 10
        }
366
367 10
        $value = (isset($import[$value])) ? $import[$value] : $default;
368
369 10
        return $this->getBooleanValue($value);
370
    }
371
372
    /**
373
     * Gets the boolean value from the string
374
     *
375
     * @param string $value  The value to check
376
     *
377
     * @return bool Returns the value of the boolean
378
     */
379 10
    private function getBooleanValue($value)
380
    {
381 10
        $value = strtolower($value);
382
383 10
        if (!$value || $value === "false" || $value === "no") {
384 10
            return false;
385
        }
386
387 9
        return true;
388
    }
389
390
    /**
391
     * Returns the filename of the resource
392
     *
393
     * @return mixed The filename
394
     */
395 3
    public function getFilename()
396
    {
397 3
        return $this->filename;
398
    }
399
400
    /**
401
     * Returns the raw content of the resource
402
     *
403
     * @return array|mixed The raw content
404
     */
405 1
    public function getRawContent()
406
    {
407 1
        return $this->raw_content;
408
    }
409
}
410