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 ( a07f0a...79e180 )
by Miles
05:56
created

FileResource::parseContent()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
ccs 11
cts 11
cp 1
rs 8.8571
cc 6
eloc 10
nc 4
nop 3
crap 6
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.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\Resource;
20
21
use Symfony\Component\Filesystem\Filesystem;
22
23
/**
24
 * File Resource enables interaction with files as resources
25
 *
26
 * @since 0.1.0
27
 */
28
class FileResource extends AbstractResource
29
{
30
    /**
31
     * Basic file interaction logic
32
     */
33
    use FileTrait;
34
35
    /**
36
     * The env separator for environment replacements
37
     *
38
     * @var string
39
     */
40
    private static $env_separator = '_ENV::';
41
42
    /**
43
     * The filename of the loaded file
44
     *
45
     * @var string
46
     */
47
    private $filename;
48
49
    /**
50
     * The parent ResourceProvider
51
     *
52
     * @var \M1\Vars\Resource\ResourceProvider
53
     */
54
    private $provider;
55
56
    /**
57
     * The raw content from the passed file
58
     *
59
     * @var mixed
60
     */
61
    private $raw_content = array();
62
63
    /**
64
     * The file resource constructor to get and parse the content from files
65
     *
66
     * @param \M1\Vars\Resource\ResourceProvider $provider The parent ResourceProvider
67
     * @param string                             $file     The passed file
68
     */
69 57
    public function __construct(ResourceProvider $provider, $file)
70
    {
71 57
        $this->provider = $provider;
72 57
        $this->vars = $provider->vars;
73
74 57
        $this->makePaths($file);
75 57
        $this->validate();
76
77 57
        $content = $this->loadContent($this->file);
78 50
        $this->raw_content = $content;
79
80 50
        if ($content) {
81 47
            $this->content = $this->searchForResources($content);
82 46
        }
83 49
    }
84
85
    /**
86
     * Make the paths used for the filename variable
87
     *
88
     * @param string $file The passed file
89
     */
90 57
    private function makePaths($file)
91
    {
92 57
        $file = realpath($file);
93
94 57
        $base_path = $this->provider->vars->getBasePath();
95
96 57
        $filesystem = new Filesystem();
97 57
        $abs_path = $filesystem->makePathRelative(
98 57
            $file,
99
            $base_path
100 57
        );
101
102 57
        $this->file = $file;
103 57
        $this->filename = rtrim($abs_path, "/");
104 57
    }
105
106
    /**
107
     * Search for imports in the files and does the replacement variables
108
     *
109
     * @param mixed $content The file content received from the loader
110
     *
111
     * @return array Returns the parsed content
112
     */
113 47
    private function searchForResources($content = array())
114
    {
115 47
        $returned_content = array();
116
117 47
        foreach ($content as $ck => $cv) {
118 47
            $returned_content = $this->parseContent($ck, $cv, $returned_content);
119 46
        }
120
121 46
        return $returned_content;
122
    }
123
124
    /**
125
     * Parses the contents inside the content array
126
     *
127
     * @param mixed $key              The key of the content array
128
     * @param mixed $value            The value of the key
129
     * @param array $returned_content The modified content array to return
130
     *
131
     * @return array Returns the modified content array
132
     */
133 47
    private function parseContent($key, $value, $returned_content)
134
    {
135 47
        if ($key === 'imports' && !is_null($value) && !empty($value)) {
136 39
            $imported_resource = $this->useImports($value);
137
138 38
            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...
139 36
                $returned_content = array_replace_recursive($returned_content, $imported_resource);
140 36
            }
141
142 46
        } elseif (is_array($value)) {
143 10
            $returned_content[$key] = $this->searchForResources($value);
144 10
        } else {
145 45
            $returned_content[$key] = $this->parseText($value);
146
        }
147
148 46
        return $returned_content;
149
    }
150
    /**
151
     * Parses the text for option and environment replacements and replaces the text
152
     *
153
     * @param string $text The text to be parsed
154
     *
155
     * @return string|null The parsed string
156
     */
157 45
    private function parseText($text)
158
    {
159 45
        if (substr($text, 0, 6) === self::$env_separator) {
160 1
            $variable = trim(substr($text, strlen(self::$env_separator)));
161
162 1
            if ($variable) {
163 1
                $value = getenv($variable);
164
165 1
                if ($value) {
166 1
                    return $value;
167
                }
168 1
            }
169 1
        } else {
170 44
            return strtr($text, $this->vars->getVariables());
171
        }
172
173 1
        return null;
174
    }
175
176
    /**
177
     * Use the import arrays to import resources
178
     *
179
     * @param mixed $imports The resources wanting to be imported
180
     *
181
     * @return array The parsed imported resources
182
     */
183 39
    private function useImports($imports)
184
    {
185 39
        $imported_resources = array();
186
187 39
        if ((is_array($imports) && $this->isAssoc($imports)) || is_string($imports)) {
188 33
            $imports = array($imports);
189 33
        }
190
191 39
        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...
192 39
            $imported_resources = $this->processImport($import, $imported_resources);
193 38
        }
194
195 38
        return $imported_resources;
196
    }
197
198
    /**
199
     * Processes the import and gets individual import if set and passes them off to import2Resources()
200
     *
201
     * @param mixed $import The import to be processed
202
     * @param array $imported_resources The array of imported resources
203
     *
204
     * @return array The parsed imported resources
205
     */
206 39
    private function processImport($import, array $imported_resources)
207
    {
208 39
        if (is_array($import) && array_key_exists('resource', $import) && is_array($import['resource'])) {
209 1
            foreach ($import['resource'] as $resource) {
210
                $temp = array(
211 1
                    'resource' => $resource,
212 1
                    'relative' => $this->isRelative($import)
213 1
                );
214
215 1
                $imported_resources = $this->import2Resource($temp, $imported_resources);
216 1
            }
217 1
        } else {
218 39
            $imported_resources = $this->import2Resource($import, $imported_resources);
219
        }
220
221 38
        return $imported_resources;
222
    }
223
224
    /**
225
     * Creates the resource from the import then imports it
226
     *
227
     * @param array|string $import The string|array to be converted to a resource
228
     * @param array $imported_resources The array of imported resources
229
     *
230
     * @return array The imported resources
231
     */
232 39
    private function import2Resource($import, array $imported_resources)
233
    {
234 39
        $resource = $this->createResource($import);
235
236 38
        if ($resource) {
237 38
            $imported_resources = $this->importResource($resource, $imported_resources);
238 38
        }
239
240 38
        return $imported_resources;
241
    }
242
243
    /**
244
     * Creates resource from the import
245
     *
246
     * @param array|string $import The import to create a resource from
247
     *
248
     * @return array|\M1\Vars\Resource\ResourceProvider The resource of the import
249
     */
250 39
    private function createResource($import)
251
    {
252 39
        if (is_array($import) && array_key_exists('resource', $import)) {
253 8
            $import_resource = $import;
254 8
            $import_resource['relative'] = $this->isRelative($import_resource);
255 39
        } elseif (is_string($import)) {
256 32
            $import_resource = array('resource' => $import, 'relative' => true);
257 32
        } else {
258
            return false;
259
        }
260
261 39
        $import_resource = new ResourceProvider(
262 39
            $this->provider->vars,
263 39
            sprintf('%s/%s', dirname($this->file), $import_resource['resource']),
264 39
            $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...
265 39
        );
266
267 38
        return $import_resource;
268
    }
269
270
    /**
271
     * Import resource into the imported resources and merge contents
272
     *
273
     * @param ResourceProvider $provider The new imported resource
274
     * @param array            $imported_resources The imported resources
275
     *
276
     * @return array The modified imported resources
277
     */
278 38
    private function importResource(ResourceProvider $provider, $imported_resources)
279
    {
280 38
        $content = $provider->getContent();
281 38
        $parent_content = $provider->getParentContent();
282
283 38
        if (!empty($content)) {
284 36
            $imported_resources = array_replace_recursive($imported_resources, $content);
285 36
        }
286
287 38
        if (!empty($parent_content)) {
288 7
            $this->provider->addParentContent($parent_content);
289 7
        }
290
291 38
        return $imported_resources;
292
    }
293
294
    /**
295
     * Returns whether the passed array is associative
296
     *
297
     * @param array $array The passed array
298
     *
299
     * @return bool Is the passed array associative
300
     */
301 9
    private function isAssoc(array $array)
302
    {
303 9
        return array_keys($array) !== range(0, count($array) - 1);
304
    }
305
306
    /**
307
     * Checks if the passed import is wanting to be merged into the parent content or relative content
308
     *
309
     * @param mixed $import The passed import
310
     *
311
     * @return bool Returns whether wanting to be a relative import
312
     */
313 8
    public function isRelative($import)
314
    {
315 8
        $relative = (isset($import['relative'])) ? $import['relative'] : true;
316
317 8
        switch (strtolower($relative)) {
318 8
            case false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strtolower($relative) of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
319 8
            case 'false':
320 8
            case 'no':
321 7
                return false;
322 7
            case true:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strtolower($relative) 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...
323 7
            case 'yes':
324 7
            case 'true':
325 7
            default:
326 7
                return true;
327
        }
328
    }
329
330
    /**
331
     * Returns the filename of the resource
332
     *
333
     * @return mixed The filename
334
     */
335 3
    public function getFilename()
336
    {
337 3
        return $this->filename;
338
    }
339
340
    /**
341
     * Returns the raw content of the resource
342
     *
343
     * @return array|mixed The raw content
344
     */
345 1
    public function getRawContent()
346
    {
347 1
        return $this->raw_content;
348
    }
349
}
350