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 ( 79e180...3094b9 )
by Miles
09:00
created

FileResource::useImports()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

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