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.

FileResource::import2Resource()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
crap 2
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     1.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 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
    /**
38
     * Enables the resource flags logic
39
     */
40
    use ResourceFlagsTrait;
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 VariableProvider
65
     *
66
     * @var \M1\Vars\Variables\VariableProvider
67
     */
68
    private $variables;
69
70
    /**
71
     * The file resource constructor to get and parse the content from files
72
     *
73
     * @param \M1\Vars\Resource\ResourceProvider $provider The parent ResourceProvider
74
     * @param string                             $file     The passed file
75
     */
76 75
    public function __construct(ResourceProvider $provider, $file)
77
    {
78 75
        $this->provider = $provider;
79 75
        $this->vars = $provider->vars;
80 75
        $this->variables = $this->vars->variables;
81
82 75
        $this->makePaths($file);
83 75
        $this->validate();
84
85 75
        $store_prefix = $this->variables->vstore->getPrefix();
86
87 75
        $content = $this->loadContent($this->file);
88 67
        $this->raw_content = $content;
89
90 67
        if ($content) {
91 63
            $this->content = $this->searchForResources($content, $store_prefix);
92
        }
93 64
    }
94
95
    /**
96
     * Make the paths used for the filename variable
97
     *
98
     * @param string $file The passed file
99
     */
100 75
    private function makePaths($file)
101
    {
102 75
        $file = realpath($file);
103
104 75
        $base_path = $this->provider->vars->getPath();
105
106 75
        $filesystem = new Filesystem();
107 75
        $abs_path = $filesystem->makePathRelative(
108 75
            $file,
109 75
            $base_path
110
        );
111
112 75
        $this->file = $file;
113 75
        $this->filename = rtrim($abs_path, "/");
114 75
    }
115
116
    /**
117
     * Search for imports in the files and does the replacement variables
118
     *
119
     * @param mixed  $content The file content received from the loader
120
     * @param string $prefix  The array prefix for the entity
121
     *
122
     * @return array Returns the parsed content
123
     */
124 63
    private function searchForResources($content = array(), $prefix = '')
125
    {
126 63
        $returned_content = array();
127
128 63
        foreach ($content as $ck => $cv) {
129 63
            $this->variables->vstore->setCurrentPrefix($prefix);
130 63
            $returned_content = $this->parseContent($ck, $cv, $returned_content, $prefix);
131
        }
132
133 60
        return $returned_content;
134
    }
135
136
    /**
137
     * Parses the contents inside the content array
138
     *
139
     * @param mixed  $key              The key of the content array
140
     * @param mixed  $value            The value of the key
141
     * @param array  $returned_content The modified content array to return
142
     * @param string $prefix           The array prefix for the entity
143
     *
144
     * @return array Returns the modified content array
145
     */
146 63
    private function parseContent($key, $value, $returned_content, $prefix)
147
    {
148 63
        if ($key === 'imports' && !is_null($value) && !empty($value)) {
149 53
            $imported_resource = $this->useImports($value);
150
151 51
            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...
152 51
                $returned_content = array_replace_recursive($returned_content, $imported_resource);
153
            }
154 58
        } elseif (is_array($value)) {
155 15
            $returned_content[$key] = $this->searchForResources(
156 15
                $value,
157 15
                $this->variables->vstore->createPrefixName($prefix, $key)
158
            );
159
        } else {
160 58
            $value = $this->parseText($value);
161 57
            $this->variables->vstore->set($prefix.$key, $value);
162 57
            $returned_content[$key] = $value;
163
        }
164
165 60
        return $returned_content;
166
    }
167
168
    /**
169
     * Parses the text for option and environment replacements and replaces the text
170
     *
171
     * @param string $text The text to be parsed
172
     *
173
     * @return string|null The parsed string
174
     */
175 63
    private function parseText($text)
176
    {
177 63
        if (is_string($text)) {
178 63
            return $this->variables->parse($text);
179
        }
180
181 10
        return $text;
182
    }
183
184
    /**
185
     * Use the import arrays to import resources
186
     *
187
     * @param mixed $imports The resources wanting to be imported
188
     *
189
     * @return array The parsed imported resources
190
     */
191 53
    private function useImports($imports)
192
    {
193 53
        $imported_resources = array();
194
195 53
        if ((is_array($imports) && $this->isAssoc($imports)) || is_string($imports)) {
196 47
            $imports = array($imports);
197
        }
198
199 53
        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...
200 53
            $imported_resources = $this->processImport($this->parseText($import), $imported_resources);
201
        }
202
203 51
        return $imported_resources;
204
    }
205
206
    /**
207
     * Processes the import and gets individual import if set and passes them off to import2Resources()
208
     *
209
     * @param mixed $import The import to be processed
210
     * @param array $imported_resources The array of imported resources
211
     *
212
     * @return array The parsed imported resources
213
     */
214 53
    private function processImport($import, array $imported_resources)
215
    {
216 53
        if (is_array($import) && array_key_exists('resource', $import) && is_array($import['resource'])) {
217 1
            foreach ($import['resource'] as $resource) {
218
                $temp = array(
219 1
                    'resource' => $resource,
220 1
                    'relative' => $this->checkBooleanValue('relative', $import),
221 1
                    'recursive' => $this->checkBooleanValue('recursive', $import),
222
                );
223
224 1
                $imported_resources = $this->import2Resource($temp, $imported_resources);
225
            }
226
        } else {
227 53
            $imported_resources = $this->import2Resource($import, $imported_resources);
228
        }
229
230 51
        return $imported_resources;
231
    }
232
233
    /**
234
     * Creates the resource from the import then imports it
235
     *
236
     * @param array|string $import The string|array to be converted to a resource
237
     * @param array $imported_resources The array of imported resources
238
     *
239
     * @return array The imported resources
240
     */
241 53
    private function import2Resource($import, array $imported_resources)
242
    {
243 53
        $resource = $this->createResource($import);
244
245 51
        if ($resource) {
246 51
            $imported_resources = $this->importResource($resource, $imported_resources);
247
        }
248
249 51
        return $imported_resources;
250
    }
251
252
    /**
253
     * Creates resource from the import
254
     *
255
     * @param array|string $import The import to create a resource from
256
     *
257
     * @return \M1\Vars\Resource\ResourceProvider The resource of the import
258
     */
259 53
    private function createResource($import)
260
    {
261 53
        if (is_array($import) && array_key_exists('resource', $import)) {
262 10
            $import_resource = $import;
263 10
            $import_resource['relative'] = $this->checkBooleanValue('relative', $import_resource);
264 10
            $import_resource['recursive'] = $this->checkBooleanValue('recursive', $import_resource);
265 44
        } elseif (is_string($import)) {
266 44
            $import_resource = array('resource' => $import, 'relative' => true, 'recursive' => true);
267
        }
268
269 53
        $import_resource = new ResourceProvider(
270 53
            $this->provider->vars,
271 53
            $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...
272 53
            $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...
273 53
            $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...
274
        );
275
276 51
        return $import_resource;
277
    }
278
279
    /**
280
     * Creates the correctly formatted resource name with paths
281
     *
282
     * @param string $resource The resource to create the import name for
283
     *
284
     * @return string The parsed resource
285
     */
286 53
    private function createImportName($resource)
287
    {
288 53
        $resource = $this->explodeResourceIfElse($resource);
289 53
        $resource_pieces = array();
290
        
291 53
        foreach ($resource as $r) {
292 53
            $parsed_r = $this->trimFlags($r);
293 53
            $parsed_r = sprintf('%s/%s', dirname($this->file), $parsed_r);
294 53
            $parsed_r = $this->replicateFlags($parsed_r, $r);
295
296 53
            $resource_pieces[] = $parsed_r;
297
        }
298
299 53
        return $this->implodeResourceIfElse($resource_pieces);
300
    }
301
302
    /**
303
     * Import resource into the imported resources and merge contents
304
     *
305
     * @param ResourceProvider $provider The new imported resource
306
     * @param array            $imported_resources The imported resources
307
     *
308
     * @return array The modified imported resources
309
     */
310 51
    private function importResource(ResourceProvider $provider, $imported_resources)
311
    {
312 51
        $content = $provider->getContent();
313 51
        $parent_content = $provider->getParentContent();
314
315 51
        if (!empty($content)) {
316 48
            $imported_resources = array_replace_recursive($imported_resources, $content);
317
        }
318
319 51
        if (!empty($parent_content)) {
320 7
            $this->provider->addParentContent($parent_content);
321
        }
322
323 51
        return $imported_resources;
324
    }
325
326
    /**
327
     * Returns whether the passed array is associative
328
     *
329
     * @param array $array The passed array
330
     *
331
     * @return bool Is the passed array associative
332
     */
333 11
    private function isAssoc(array $array)
334
    {
335 11
        return array_keys($array) !== range(0, count($array) - 1);
336
    }
337
338
    /**
339
     * Checks if the passed boolean value is true or false
340
     *
341
     * @param string $value  The value to check
342
     * @param mixed  $import The passed import
343
     *
344
     * @return bool Returns the value of the boolean
345
     */
346 10
    public function checkBooleanValue($value, $import)
347
    {
348 10
        $default = false;
349
350 10
        if ($value === 'relative') {
351 10
            $default = true;
352
        }
353
354 10
        $value = (isset($import[$value])) ? $import[$value] : $default;
355
356 10
        return $this->getBooleanValue($value);
357
    }
358
359
    /**
360
     * Gets the boolean value from the string
361
     *
362
     * @param string $value  The value to check
363
     *
364
     * @return bool Returns the value of the boolean
365
     */
366 10
    private function getBooleanValue($value)
367
    {
368 10
        $value = strtolower($value);
369
370 10
        if (!$value || $value === "false" || $value === "no") {
371 10
            return false;
372
        }
373
374 9
        return true;
375
    }
376
377
    /**
378
     * Returns the filename of the resource
379
     *
380
     * @return string The filename
381
     */
382 3
    public function getFilename()
383
    {
384 3
        return $this->filename;
385
    }
386
387
    /**
388
     * Returns the raw content of the resource
389
     *
390
     * @return array|mixed The raw content
391
     */
392 1
    public function getRawContent()
393
    {
394 1
        return $this->raw_content;
395
    }
396
}
397