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 ( bca756...aea469 )
by Miles
03:04
created

FileResource::createImportName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

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