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

FileResource::getRawContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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 70
    public function __construct(ResourceProvider $provider, $file)
74
    {
75 70
        $this->provider = $provider;
76 70
        $this->vars = $provider->vars;
77
78 70
        $this->makePaths($file);
79 70
        $this->validate();
80
81 70
        $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 70
    private function makePaths($file)
95
    {
96 70
        $file = realpath($file);
97
98 70
        $base_path = $this->provider->vars->getBasePath();
99
100 70
        $filesystem = new Filesystem();
101 70
        $abs_path = $filesystem->makePathRelative(
102 70
            $file,
103
            $base_path
104 70
        );
105
106 70
        $this->file = $file;
107 70
        $this->filename = rtrim($abs_path, "/");
108 70
    }
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 49
            $suppress = false;
290 49
            $recursive = false;
291
292 49
            if ($this->checkSuppression($r)) {
293 1
                $suppress = true;
294 1
                $r = trim($r, "@");
295 1
            }
296
            
297 49
            if ($this->checkRecursive($r)) {
298 2
                $recursive = true;
299 2
                $r = trim($r, "*");
300 2
            }
301
302 49
            $r = sprintf('%s/%s', dirname($this->file), $r);
303
304 49
            if ($suppress) {
305 1
                $r = "@".$r;
306 1
            }
307
308 49
            if ($recursive) {
309 2
                $r = $r."*";
310 2
            }
311
312 49
            $resource_pieces[] = $r;
313 49
        }
314
315 49
        return $this->implodeResourceIfElse($resource_pieces);
316
317
    }
318
319
    /**
320
     * Import resource into the imported resources and merge contents
321
     *
322
     * @param ResourceProvider $provider The new imported resource
323
     * @param array            $imported_resources The imported resources
324
     *
325
     * @return array The modified imported resources
326
     */
327 47
    private function importResource(ResourceProvider $provider, $imported_resources)
328
    {
329 47
        $content = $provider->getContent();
330 47
        $parent_content = $provider->getParentContent();
331
332 47
        if (!empty($content)) {
333 44
            $imported_resources = array_replace_recursive($imported_resources, $content);
334 44
        }
335
336 47
        if (!empty($parent_content)) {
337 7
            $this->provider->addParentContent($parent_content);
338 7
        }
339
340 47
        return $imported_resources;
341
    }
342
343
    /**
344
     * Returns whether the passed array is associative
345
     *
346
     * @param array $array The passed array
347
     *
348
     * @return bool Is the passed array associative
349
     */
350 11
    private function isAssoc(array $array)
351
    {
352 11
        return array_keys($array) !== range(0, count($array) - 1);
353
    }
354
355
    /**
356
     * Checks if the passed boolean value is true or false
357
     *
358
     * @param string $value  The value to check
359
     * @param mixed  $import The passed import
360
     *
361
     * @return bool Returns the value of the boolean
362
     */
363 10
    public function checkBooleanValue($value, $import)
364
    {
365 10
        $default = false;
366
367 10
        if ($value === 'relative') {
368 10
            $default = true;
369 10
        }
370 10
        $value = (isset($import[$value])) ? $import[$value] : $default;
371
372 10
        switch (strtolower($value)) {
373 10
            case false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strtolower($value) of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
374 10
            case 'false':
375 10
            case 'no':
376 10
                $value = false;
377 10
                break;
378 9
            case true:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strtolower($value) of type string to the boolean true. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
379 9
            case 'yes':
380 9
            case 'true':
381 9
            default:
382 9
                $value = true;
383 9
                break;
384 10
        }
385
386 10
        return $value;
387
    }
388
389
    /**
390
     * Returns the filename of the resource
391
     *
392
     * @return mixed The filename
393
     */
394 3
    public function getFilename()
395
    {
396 3
        return $this->filename;
397
    }
398
399
    /**
400
     * Returns the raw content of the resource
401
     *
402
     * @return array|mixed The raw content
403
     */
404 1
    public function getRawContent()
405
    {
406 1
        return $this->raw_content;
407
    }
408
}
409