DefinitionParser   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 12
eloc 26
c 2
b 1
f 0
dl 0
loc 121
ccs 0
cts 28
cp 0
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A parse() 0 34 6
A setAllowedKeys() 0 5 1
A addShortKeys() 0 7 2
A isAllowedKey() 0 3 2
A normalizeKey() 0 3 1
1
<?php
2
3
namespace Rexlabs\Smokescreen\Definition;
4
5
use Rexlabs\Smokescreen\Exception\ParseDefinitionException;
6
use Rexlabs\Smokescreen\Helpers\StrHelper;
7
8
class DefinitionParser
9
{
10
    /**
11
     * A list of keys that are allowed to be present.
12
     *
13
     * @var array
14
     */
15
    protected $allowedKeys = [];
16
17
    /**
18
     * Short keys map a shortcut key to a specific directive.
19
     *
20
     * @var array
21
     */
22
    protected $shortKeys = [];
23
24
    /**
25
     * Parses a definition string into an array.
26
     * Supports a value like integer|arg1:val|arg2:val|arg3.
27
     *
28
     * @param string $str
29
     *
30
     * @throws \Rexlabs\Smokescreen\Exception\ParseDefinitionException
31
     *
32
     * @return array
33
     */
34
    public function parse($str): array
35
    {
36
        $definition = [];
37
38
        if (empty($str)) {
39
            // Return empty definition
40
            return $definition;
41
        }
42
43
        // Directives are delimited with a pipe operator
44
        foreach (preg_split('/\s*\|\s*/', $str) as $directive) {
45
            // May consist of "directive:value" or it may just be "directive".
46
            $parts = explode(':', $directive, 2);
47
            $key = $parts[0];
48
            $value = $parts[1] ?? null;
49
50
            if (isset($this->shortKeys[$key])) {
51
                if ($value !== null) {
52
                    // If a value was also provided, we'll store that in a separate entry.
53
                    $definition[$this->normalizeKey($key)] = $value;
54
                }
55
                $value = $key;
56
                $key = $this->shortKeys[$key];
57
            }
58
59
            if (!$this->isAllowedKey($key)) {
60
                throw new ParseDefinitionException("Unsupported key '$key'");
61
            }
62
63
            // Normalise our directive (as snake_case) and store the value.
64
            $definition[$this->normalizeKey($key)] = $value;
65
        }
66
67
        return $definition;
68
    }
69
70
    /**
71
     * Normalize a directive key.
72
     *
73
     * @param string $key
74
     *
75
     * @return string
76
     */
77
    protected function normalizeKey($key): string
78
    {
79
        return StrHelper::snakeCase(strtolower($key));
80
    }
81
82
    /**
83
     * Set a list of keys which are allowed.
84
     * An empty array will allow any key.
85
     * An exception will be thrown while parsing when the allowed keys are not empty, and the
86
     * directive key is not present in this list.
87
     *
88
     * @param array $keys
89
     *
90
     * @return $this
91
     */
92
    public function setAllowedKeys(array $keys)
93
    {
94
        $this->allowedKeys = $keys;
95
96
        return $this;
97
    }
98
99
    /**
100
     * Determine if a given key is permitted.
101
     *
102
     * @param $key
103
     *
104
     * @return bool
105
     */
106
    protected function isAllowedKey($key): bool
107
    {
108
        return empty($this->allowedKeys) || \in_array($key, $this->allowedKeys, true);
109
    }
110
111
    /**
112
     * Register one or more shortcut keys which map to a directive.
113
     * For example a shortcut key of 'integer' can mapped to a directive of 'type'.
114
     * This would allow a user to specify a directive of simply 'integer', instead
115
     * of 'type:integer'.
116
     *
117
     * @param string $directive
118
     * @param array  $keys
119
     *
120
     * @return $this
121
     */
122
    public function addShortKeys(string $directive, array $keys)
123
    {
124
        foreach ($keys as $key) {
125
            $this->shortKeys[$key] = $directive;
126
        }
127
128
        return $this;
129
    }
130
}
131