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

DefinitionParser::normalizeKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 2
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
     * @return array
31
     * @throws \Rexlabs\Smokescreen\Exception\ParseDefinitionException
32
     */
33
    public function parse($str): array
34
    {
35
        $definition = [];
36
37
        if (empty($str)) {
38
            // Return empty definition
39
            return $definition;
40
        }
41
42
        // Directives are delimited with a pipe operator
43
        foreach (preg_split('/\s*\|\s*/', $str) as $directive) {
44
            // May consist of "directive:value" or it may just be "directive".
45
            $parts = explode(':', $directive, 2);
46
            $key = $parts[0];
47
            $value = $parts[1] ?? null;
48
49
            if (isset($this->shortKeys[$key])) {
50
                if ($value !== null) {
51
                    // If a value was also provided, we'll store that in a separate entry.
52
                    $definition[$this->normalizeKey($key)] = $value;
53
                }
54
                $value = $key;
55
                $key = $this->shortKeys[$key];
56
            }
57
58
            if (!$this->isAllowedKey($key)) {
59
                throw new ParseDefinitionException("Unsupported key '$key'");
60
            }
61
62
            // Normalise our directive (as snake_case) and store the value.
63
            $definition[$this->normalizeKey($key)] = $value;
64
        }
65
66
67
68
        return $definition;
69
    }
70
71
    /**
72
     * Normalize a directive key
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
     * @param array $keys
88
     *
89
     * @return $this
90
     */
91
    public function setAllowedKeys(array $keys)
92
    {
93
        $this->allowedKeys = $keys;
94
95
        return $this;
96
    }
97
98
    /**
99
     * Determine if a given key is permitted.
100
     * @param $key
101
     *
102
     * @return bool
103
     */
104
    protected function isAllowedKey($key): bool
105
    {
106
        return empty($this->allowedKeys) || \in_array($key, $this->allowedKeys, true);
107
    }
108
109
    /**
110
     * Register one or more shortcut keys which map to a directive.
111
     * For example a shortcut key of 'integer' can mapped to a directive of 'type'.
112
     * This would allow a user to specify a directive of simply 'integer', instead
113
     * of 'type:integer'.
114
     *
115
     * @param string $directive
116
     * @param array  $keys
117
     *
118
     * @return $this
119
     */
120
    public function addShortKeys(string $directive, array $keys)
121
    {
122
        foreach ($keys as $key) {
123
            $this->shortKeys[$key] = $directive;
124
        }
125
126
        return $this;
127
    }
128
}