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.

VariableParser   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 331
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 5
dl 0
loc 331
ccs 103
cts 103
cp 1
rs 9.2
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A parse() 0 14 3
A fetchVariableMatches() 0 10 4
A fetchVariable() 0 20 5
A hasParameterExpansion() 0 10 3
A fetchParameterExpansion() 0 17 2
A fetchParameterExpansionType() 0 8 2
A fetchParameterExpansionSymbol() 0 14 2
A splitVariableDefault() 0 14 3
A parseVariableParameter() 0 8 3
A assignVariableParameterDefault() 0 10 3
A hasVariable() 0 12 3
A getVariable() 0 12 3
A doReplacements() 0 15 3

How to fix   Complexity   

Complex Class

Complex classes like VariableParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use VariableParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the m1\env library
5
 *
6
 * (c) m1 <[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/env
12
 * @version     2.0.0
13
 * @author      Miles Croxford <[email protected]>
14
 * @copyright   Copyright (c) Miles Croxford <[email protected]>
15
 * @license     http://github.com/m1/env/blob/master/LICENSE.md
16
 * @link        http://github.com/m1/env/blob/master/README.md Documentation
17
 */
18
19
namespace M1\Env\Parser;
20
21
use M1\Env\Exception\ParseException;
22
23
/**
24
 * The value parser for Env
25
 *
26
 * @since 1.1.0
27
 */
28
class VariableParser extends AbstractParser
29
{
30
    /**
31
     * The regex to get variables '$(VARIABLE)' in .env
32
     * Unescaped: ${(.*?)}
33
     *
34
     * @var string REGEX_ENV_VARIABLE
35
     */
36
    const REGEX_ENV_VARIABLE = '\\${(.*?)}';
37
38
    /**
39
     * The symbol for the assign default value parameter expansion
40
     *
41
     * @var string SYMBOL_ASSIGN_DEFAULT_VALUE
42
     */
43
    const SYMBOL_ASSIGN_DEFAULT_VALUE = '=';
44
45
    /**
46
     * The symbol for the default value parameter expansion
47
     *
48
     * @var string SYMBOL_DEFAULT_VALUE
49
     */
50
    const SYMBOL_DEFAULT_VALUE = '-';
51
52
    /**
53
     * Variables context
54
     *
55
     * @var array
56
     */
57
    private $context;
58
59
    /**
60
     * {@inheritdoc}
61
     *
62
     * @param \M1\Env\Parser $parser The parent parser
63
     * @param array $context Variables context
64
     */
65 66
    public function __construct($parser, array $context = array())
66
    {
67 66
        parent::__construct($parser);
68
69 66
        $this->context = $context;
70 66
    }
71
72
    /**
73
     * Parses a .env variable
74
     *
75
     * @param string $value         The value to parse
76
     * @param bool   $quoted_string Is the value in a quoted string
77
     *
78
     * @return string The parsed value
79
     */
80 39
    public function parse($value, $quoted_string = false)
81
    {
82 39
        $matches = $this->fetchVariableMatches($value);
83
84 39
        if (is_array($matches)) {
85 21
            if ($this->parser->string_helper->isVariableClone($value, $matches, $quoted_string)) {
86 21
                return $this->fetchVariable($value, $matches[1][0], $matches, $quoted_string);
87
            }
88
89 12
            $value = $this->doReplacements($value, $matches, $quoted_string);
90 12
        }
91
92 33
        return $value;
93
    }
94
95
    /**
96
     * Get variable matches inside a string
97
     *
98
     * @param string $value The value to parse
99
     *
100
     * @return array The variable matches
101
     */
102 39
    private function fetchVariableMatches($value)
103
    {
104 39
        preg_match_all('/' . self::REGEX_ENV_VARIABLE . '/', $value, $matches);
105
106 39
        if (!is_array($matches) || !isset($matches[0]) || empty($matches[0])) {
107 30
            return false;
108
        }
109
110 21
        return $matches;
111
    }
112
113
    /**
114
     * Parses a .env variable
115
     *
116
     * @param string $value The value to parse
117
     * @param string $variable_name The variable name to get
118
     * @param array $matches The matches of the variables
119
     * @param bool $quoted_string Is the value in a quoted string
120
     *
121
     * @return string The parsed value
122
     * @throws \M1\Env\Exception\ParseException If the variable can not be found
123
     */
124 21
    private function fetchVariable($value, $variable_name, $matches, $quoted_string)
125
    {
126 21
        if ($this->hasParameterExpansion($variable_name)) {
127 9
            $replacement = $this->fetchParameterExpansion($variable_name);
128 18
        } elseif ($this->hasVariable($variable_name)) {
129 12
            $replacement = $this->getVariable($variable_name);
130 12
        } else {
131 3
            throw new ParseException(
132 3
                sprintf('Variable has not been defined: %s', $variable_name),
133 3
                $value,
134 3
                $this->parser->line_num
135 3
            );
136
        }
137
138 15
        if ($this->parser->string_helper->isBoolInString($replacement, $quoted_string, count($matches[0]))) {
139 6
            $replacement = ($replacement) ? 'true' : 'false';
140 6
        }
141
142 15
        return $replacement;
143
    }
144
145
    /**
146
     * Checks to see if the variable has a parameter expansion
147
     *
148
     * @param string $variable The variable to check
149
     *
150
     * @return bool Does the variable have a parameter expansion
151
     */
152 21
    private function hasParameterExpansion($variable)
153
    {
154 21
        if ((strpos($variable, self::SYMBOL_DEFAULT_VALUE) !== false) ||
155 21
            (strpos($variable, self::SYMBOL_ASSIGN_DEFAULT_VALUE) !== false)
156 21
        ) {
157 9
            return true;
158
        }
159
160 15
        return false;
161
    }
162
163
    /**
164
     * Fetches and sets the parameter expansion
165
     *
166
     * @param string $variable_name The parameter expansion inside this to fetch
167
     *
168
     * @return string The parsed value
169
     */
170 9
    private function fetchParameterExpansion($variable_name)
171
    {
172 9
        $parameter_type = $this->fetchParameterExpansionType($variable_name);
173
174 9
        list($parameter_symbol, $empty_flag) = $this->fetchParameterExpansionSymbol($variable_name, $parameter_type);
175 9
        list($variable, $default) = $this->splitVariableDefault($variable_name, $parameter_symbol);
176
177 6
        $value = $this->getVariable($variable);
178
179 6
        return $this->parseVariableParameter(
180 6
            $variable,
181 6
            $default,
182 6
            $this->hasVariable($variable),
183 6
            $empty_flag && empty($value),
184
            $parameter_type
185 6
        );
186
    }
187
188
    /**
189
     * Fetches the parameter expansion type
190
     *
191
     * @param string $variable_name The parameter expansion type to get from this
192
     *
193
     * @return string The parameter expansion type
194
     */
195 9
    private function fetchParameterExpansionType($variable_name)
196
    {
197 9
        if (strpos($variable_name, self::SYMBOL_ASSIGN_DEFAULT_VALUE) !== false) {
198 9
            return 'assign_default_value';
199
        }
200
201 6
        return 'default_value'; // self::DEFAULT_VALUE_SYMBOL
202
    }
203
204
    /**
205
     * Fetches the parameter type symbol
206
     *
207
     * @param string $variable_name The variable
208
     * @param string $type          The type of parameter expansion
209
     *
210
     * @return array The symbol and if there is a empty check
211
     */
212 9
    private function fetchParameterExpansionSymbol($variable_name, $type)
213
    {
214 9
        $class = new \ReflectionClass($this);
215 9
        $symbol = $class->getConstant('SYMBOL_'.strtoupper($type));
216 9
        $pos = strpos($variable_name, $symbol);
217
218 9
        $check_empty = substr($variable_name, ($pos - 1), 1) === ":";
219
220 9
        if ($check_empty) {
221 9
            $symbol = sprintf(":%s", $symbol);
222 9
        }
223
224 9
        return array($symbol, $check_empty);
225
    }
226
227
    /**
228
     * Splits the parameter expansion into variable and default
229
     *
230
     * @param string $variable_name    The variable name to split
231
     * @param string $parameter_symbol The parameter expansion symbol
232
     *
233
     * @throws \M1\Env\Exception\ParseException If the parameter expansion if not valid syntax
234
     *
235
     * @return array The split variable and default value
236
     */
237 9
    private function splitVariableDefault($variable_name, $parameter_symbol)
238
    {
239 9
        $variable_default = explode($parameter_symbol, $variable_name, 2);
240
241 9
        if (count($variable_default) !== 2 || empty($variable_default[1])) {
242 3
            throw new ParseException(
243 3
                'You must have valid parameter expansion syntax, eg. ${parameter:=word}',
244 3
                $variable_name,
245 3
                $this->parser->line_num
246 3
            );
247
        }
248
249 6
        return array(trim($variable_default[0]), trim($variable_default[1]));
250
    }
251
252
253
    /**
254
     * Parses and sets the variable and default if needed
255
     *
256
     * @param string $variable The variable to parse
257
     * @param string $default  The default value
258
     * @param bool   $exists   Does the variable exist
259
     * @param bool   $empty    Is there the variable empty if exists and the empty flag is set
260
     * @param string $type     The type of parameter expansion
261
     *
262
     * @return string The parsed value
263
     */
264 6
    private function parseVariableParameter($variable, $default, $exists, $empty, $type)
265
    {
266 6
        if ($exists && !$empty) {
267 6
            return $this->getVariable($variable);
268
        }
269
270 6
        return $this->assignVariableParameterDefault($variable, $default, $empty, $type);
271
    }
272
273
    /**
274
     * Parses and sets the variable parameter to default
275
     *
276
     * @param string $variable The variable to parse
277
     * @param string $default  The default value
278
     * @param bool   $empty    Is there the variable empty if exists and the empty flag is set
279
     * @param string $type     The type of parameter expansion
280
     *
281
     * @return string The parsed default value
282
     */
283 6
    private function assignVariableParameterDefault($variable, $default, $empty, $type)
284
    {
285 6
        $default = $this->parser->value_parser->parse($default);
286
287 6
        if ($type === "assign_default_value" && $empty) {
288 6
            $this->parser->lines[$variable] = $default;
289 6
        }
290
291 6
        return $default;
292
    }
293
294
    /**
295
     * Checks to see if a variable exists
296
     *
297
     * @param string $variable The variable name to get
298
     *
299
     * @return bool
300
     */
301 18
    private function hasVariable($variable)
302
    {
303 18
        if (array_key_exists($variable, $this->parser->lines)) {
304 15
            return true;
305
        }
306
307 12
        if (array_key_exists($variable, $this->context)) {
308 3
            return true;
309
        }
310
311 9
        return false;
312
    }
313
314
    /**
315
     * Get variable value
316
     *
317
     * @param string $variable
318
     *
319
     * @return mixed
320
     */
321 15
    private function getVariable($variable)
322
    {
323 15
        if (array_key_exists($variable, $this->parser->lines)) {
324 15
            return $this->parser->lines[$variable];
325
        }
326
327 9
        if (array_key_exists($variable, $this->context)) {
328 3
            return $this->context[$variable];
329
        }
330
331 6
        return null;
332
    }
333
334
    /**
335
     * Do the variable replacements
336
     *
337
     * @param string $value         The value to throw an error with if doesn't exist
338
     * @param array  $matches       The matches of the variables
339
     * @param bool   $quoted_string Is the value in a quoted string
340
     *
341
     * @return string The parsed value
342
     */
343 12
    public function doReplacements($value, $matches, $quoted_string)
344
    {
345 12
        $replacements = array();
346
347 12
        for ($i = 0; $i <= (count($matches[0]) - 1); $i++) {
348 12
            $replacement = $this->fetchVariable($value, $matches[1][$i], $matches, $quoted_string);
349 12
            $replacements[$matches[0][$i]] = $replacement;
350 12
        }
351
352 12
        if (!empty($replacements)) {
353 12
            $value = strtr($value, $replacements);
354 12
        }
355
356 12
        return $value;
357
    }
358
}
359