Completed
Pull Request — master (#9)
by Jodie
02:15
created

DefinitionParser::parse()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 34
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 0
cts 17
cp 0
rs 8.439
c 0
b 0
f 0
cc 6
eloc 16
nc 8
nop 1
crap 42
1
<?php
2
3
namespace Rexlabs\Smokescreen\Definition;
4
5
use Rexlabs\Smokescreen\Exception\ParseDefinitionException;
6
7
class DefinitionParser
8
{
9
    /**
10
     * A list of keys that are allowed to be present
11
     *
12
     * @var array
13
     */
14
    protected $allowedKeys = [];
15
16
    /**
17
     * Short keys map a shortcut key to a specific directive.
18
     *
19
     * @var array
20
     */
21
    protected $shortKeys = [];
22
23
    /**
24
     * Parses a definition string into an array.
25
     * Supports a value like integer|arg1:val|arg2:val|arg3
26
     *
27
     * @param string $str
28
     *
29
     * @return array
30
     * @throws \Rexlabs\Smokescreen\Exception\ParseDefinitionException
31
     */
32
    public function parse($str): array
33
    {
34
        $definition = [];
35
36
        if (empty($str)) {
37
            // Return empty definition
38
            return $definition;
39
        }
40
41
        // Directives are delimited with a pipe operator
42
        foreach (preg_split('/\s*\|\s*/', $str) as $directive) {
43
            // May consist of "directive:value" or it may just be "directive".
44
            $parts = explode(':', $directive, 2);
45
            $key = $parts[0];
46
            $value = $parts[1] ?? null;
47
48
            if (isset($this->shortKeys[$key])) {
49
                if ($value !== null) {
50
                    // If a value was also provided, we'll store that in a separate entry.
51
                    $definition[$this->normalizeKey($key)] = $value;
52
                }
53
                $key = $this->shortKeys[$key];
54
                $value = $key;
55
            }
56
57
            if (!$this->isAllowedKey($key)) {
58
                throw new ParseDefinitionException("Unsupported key '$key'");
59
            }
60
61
            // Normalise our directive (as snake_case) and store the value.
62
            $definition[$this->normalizeKey($key)] = $value;
63
        }
64
65
        return $definition;
66
    }
67
68
    /**
69
     * Normalize a directive key
70
     * @param string $key
71
     *
72
     * @return string
73
     */
74
    protected function normalizeKey($key)
75
    {
76
        return StrHelper::snakeCase(strtolower($key));
0 ignored issues
show
Bug introduced by
The type Rexlabs\Smokescreen\Definition\StrHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
77
    }
78
79
    /**
80
     * Set a list of keys which are allowed.
81
     * An empty array will allow any key.
82
     * An exception will be thrown while parsing when the allowed keys are not empty, and the
83
     * directive key is not present in this list.
84
     * @param array $keys
85
     *
86
     * @return $this
87
     */
88
    public function setAllowedKeys(array $keys)
89
    {
90
        $this->allowedKeys = $keys;
91
92
        return $this;
93
    }
94
95
    /**
96
     * Determine if a given key is permitted.
97
     * @param $key
98
     *
99
     * @return bool
100
     */
101
    protected function isAllowedKey($key): bool
102
    {
103
        return empty($this->allowedKeys) || \in_array($key, $this->allowedKeys, true);
104
    }
105
106
    /**
107
     * Register one or more shortcut keys which map to a directive.
108
     * For example a shortcut key of 'integer' can mapped to a directive of 'type'.
109
     * This would allow a user to specify a directive of simply 'integer', instead
110
     * of 'type:integer'.
111
     *
112
     * @param string $directive
113
     * @param array  $keys
114
     *
115
     * @return $this
116
     */
117
    public function addShortKeys(string $directive, array $keys)
118
    {
119
        foreach ($keys as $key) {
120
            $this->shortKeys[$key] = $directive;
121
        }
122
123
        return $this;
124
    }
125
}