Passed
Push — master ( 3dce9d...23e869 )
by José
02:18 queued 11s
created

AnnotationParserInterface::parseString()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 4
nop 1
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace SimpleAnnotation;
4
5
use SimpleAnnotation\Concerns\ParserInterface;
6
use SimpleAnnotation\Concerns\ParsedAnnotationInterface;
7
use String\Sanitizer;
8
use String\StringManipulator;
9
10
/**
11
 * The class responsible for parsing the annotations.
12
 *
13
 * @package SimpleAnnotation
14
 */
15
final class AnnotationParserInterface implements ParserInterface
16
{
17
    /**
18
     * The regexp pattern to split the tags from values in annotations.
19
     * @var string
20
     */
21
    private string $tagsPattern = '/@([a-z]+[a-z0-9_]*)(.*)\s{1,}/i';
22
23
    /**
24
     * The regexp pattern to identify numbers, integer or double.
25
     * @var string
26
     */
27
    private string $numberPattern = '/^[-]?[0-9]+([\.][0-9]+)?$/';
28
29
    /** @var ParsedAnnotationInterface */
30
    private ParsedAnnotationInterface $annotationParsed;
31
32
    /**
33
     * AnnotationParserInterface constructor.
34
     */
35 34
    public function __construct()
36
    {
37 34
        $this->initializeAnnotationParsed();
38 34
    }
39
40
    /**
41
     * Initializes the AnnotationParsedInterface object.
42
     */
43 34
    private function initializeAnnotationParsed()
44
    {
45 34
        $this->annotationParsed = new AnnotationParsedInterface();
46 34
    }
47
48
    /**
49
     * The method that coordinates the annotation parsing.
50
     *
51
     * @param string $docBlock
52
     * @return ParsedAnnotationInterface
53
     */
54 28
    public function parse(string $docBlock): ParsedAnnotationInterface
55
    {
56
        // Have to initialize every parse to clean the previous parsed values, to not "add" values that don't exist.
57 28
        $this->initializeAnnotationParsed();
58
59
        // Separate the annotations tags (position 1) and it's values (position 2)
60 28
        $matches = [];
61 28
        preg_match_all($this->tagsPattern, $docBlock, $matches);
62
63
        // Iterate then and parse each one
64 28
        foreach ($matches[1] as $key => $value) {
65 25
            $this->annotationParsed->{$value} = $this->parseAnnotationValue(trim($matches[2][$key]));
66
        }
67
68 28
        return $this->annotationParsed;
69
    }
70
71
    /**
72
     * The method that effectively parse the annotation values.
73
     *
74
     * @param string $value
75
     * @return bool|string|double|array|object|null
76
     */
77 25
    private function parseAnnotationValue(string $value)
78
    {
79
        // The annotation just exists (true value)
80 25
        if (empty($value)) {
81 3
            return true;
82
        }
83
84 25
        $firstLetter = $value[0];
85 25
        $lastLetter = StringManipulator::getLastLetter($value);
86
87 25
        if ($firstLetter === '[' && $lastLetter === ']') { // ARRAY
88 8
            $value = $this->parseArray($value);
89 25
        } elseif ($firstLetter === '{' && $lastLetter === '}') { // JSON / OBJECT
90 8
            $value = $this->parseJson($value);
91
        } else {
92 25
            if (preg_match($this->numberPattern, $value)) { // NUMERIC
93 8
                $value = $this->parseNumeric($value);
94
            } else { // BOOL, NULL and STRING
95 25
                $value = $this->parseBoolNullAndString($value);
96
            }
97
        }
98
99 25
        return $value;
100
    }
101
102
    /**
103
     * Parse a string representation of an one dimensional array into an array.
104
     *
105
     * @param string $value
106
     * @return array
107
     */
108 8
    private function parseArray(string $value): array
109
    {
110
        // Mount the array
111 8
        $value = explode(',', Sanitizer::removeFirstAndLastCharacters($value));
112
113
        // Sanitize the array values
114 8
        $value = array_map(function($v) {
115 8
            $v = trim($v);
116
117 8
            if ($v[0] === '"' || $v[0] === "'") {
118 8
                $v = Sanitizer::removeFirstCharacter($v);
119
            }
120
121 8
            if (StringManipulator::getLastLetter($v) === '"' || StringManipulator::getLastLetter($v) === "'") {
122 8
                $v = Sanitizer::removeLastCharacter($v);
123
            }
124
125 8
            return $v;
126 8
        }, $value);
127
128 8
        return $value;
129
    }
130
131
    /**
132
     * Parse a json string into an object.
133
     *
134
     * @param string $value
135
     * @return object
136
     */
137 8
    private function parseJson(string $value)
138
    {
139 8
        return json_decode($value);
140
    }
141
142
    /**
143
     * Parse a numeric string into an int or a float number.
144
     *
145
     * @param string $value
146
     * @return int|float
147
     */
148 8
    private function parseNumeric(string $value)
149
    {
150 8
        return ($value + 0);
151
    }
152
153
    /**
154
     * Parse a string into a bool, null or a string without quotation marks.
155
     *
156
     * @param string $value
157
     * @return bool|string|null
158
     */
159 25
    private function parseBoolNullAndString(string $value)
160
    {
161 25
        switch (mb_strtolower($value)) {
162 25
            case 'true':
163 8
                $value = true;
164 8
                break;
165 25
            case 'false':
166 3
                $value = false;
167 3
                break;
168 25
            case 'null':
169 3
                $value = null;
170 3
                break;
171
            default: // STRING
172 25
                $value = $this->parseString($value);
173 25
                break;
174
        }
175
176 25
        return $value;
177
    }
178
179
    /**
180
     * Remove the quotation marks of a string.
181
     *
182
     * @param string $value
183
     * @return string
184
     */
185 25
    private function parseString(string $value): string
186
    {
187 25
        $firstLetter = $value[0];
188 25
        $lastLetter = StringManipulator::getLastLetter($value);
189
190
        // Remove explicit quotation marks for strings
191 25
        if ($firstLetter === "'" || $firstLetter === '"') {
192 8
            $value = Sanitizer::removeFirstCharacter($value);
193
        }
194
195 25
        if ($lastLetter === "'" || $lastLetter === '"') {
196 8
            $value = Sanitizer::removeLastCharacter($value);
197
        }
198
199 25
        return $value;
200
    }
201
}
202