Test Failed
Push — master ( ef12af...52cb59 )
by Vincent
06:49
created

HttpFieldPath::concat()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 18
ccs 6
cts 6
cp 1
rs 9.9
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Bdf\Form\Child\Http;
4
5
/**
6
 * Represents the HTTP field path to build
7
 * Handles prefix and array key fields
8
 *
9
 * Note: This class is immutable, any modifier will return a new instance
10
 *
11
 * <code>
12
 * $path = HttpFieldPath::named('root'); // Create the root field
13
 * echo $path->get(); // "root"
14
 * echo $path->add('bar')->get(); // Array element field : "root[bar]"
15
 * echo $path->prefix('p_')->add('bar')->get(); // Add a prefix for the sub element : "root[p_bar]"
16
 * </code>
17
 */
18
final class HttpFieldPath
19
{
20
    /**
21
     * @var HttpFieldPath|null
22
     */
23
    private static $empty;
24
25
    /**
26
     * @var string
27
     */
28
    private $root = '';
29
30
    /**
31
     * @var string
32
     */
33
    private $path = '';
34
35
    /**
36
     * @var string
37
     */
38
    private $prefix = '';
39
40
    /**
41
     * HttpFieldPath constructor.
42 42
     * Note: prefer use the static methods instead of the constructor
43
     *
44 42
     * @param string $root
45 42
     * @param string $path The path
46 42
     * @param string $prefix The prefix
47
     */
48
    public function __construct(string $root = '', string $path = '', string $prefix = '')
49
    {
50
        $this->root = $root;
51
        $this->path = $path;
52
        $this->prefix = $prefix;
53
    }
54
55
    /**
56
     * Add a new sub array key to the field path :
57
     * - If the current path is the root (i.e. empty path), will return a path consisting of the name by setting the "root" field value
58 16
     * - If the path is not the root (i.e. not empty path), the name will be added at end, enclosed by "[]"
59
     * - In any case, if there is a prefix, it will be added before the name
60 16
     *
61
     * @param string $name The element name to add
62 16
     *
63 16
     * @return static The new path instance
64
     */
65 16
    public function add(string $name): self
66
    {
67
        $newPath = clone $this;
68
69
        if ($this->root === '') {
70
            $newPath->root = $this->prefix.$name;
71
        } else {
72
            $newPath->path .= '['.$this->prefix.$name.']';
73
        }
74
75
        $newPath->prefix = '';
76 6
77
        return $newPath;
78 6
    }
79
80 6
    /**
81
     * Concatenate two field paths
82 6
     * The result consists of the current path followed by the $other path
83
     *
84
     * - If the other path has a root but not the current one, use the root and path of other, prefixed by the current prefix, and replace current prefix by the prefix of other
85
     * - If the other path has a root and also the current one, append the root and the path of the other to the current, wrap the other's root with [], and replace current prefix by the prefix of other
86
     * - The the other as no root, only append its prefix to the current one
87
     *
88
     * @param HttpFieldPath $other The next field path
89
     *
90 42
     * @return static The new path instance
91
     */
92 42
    public function concat(HttpFieldPath $other): self
93 7
    {
94
        $newPath = clone $this;
95
96 40
        if ($other->root !== '') {
97 39
            if ($this->root === '') {
98
                $newPath->root = $this->prefix.$other->root;
99
                $newPath->path = $other->path;
100 2
            } else {
101
                $newPath->path .= '['.$this->prefix.$other->root.']'.$other->path;
102
            }
103
104
            $newPath->prefix = $other->prefix;
105
        } else {
106
            $newPath->prefix .= $other->prefix;
107
        }
108 37
109
        return $newPath;
110 37
    }
111
112
    /**
113
     * Add a prefix for the next element
114
     * The prefix will be appended at the end of previous prefixes, so when chaining prefixed, the prefixes order will be kept
115
     *
116
     * @param string $name
117
     *
118 1
     * @return static The new path instance
119
     */
120 1
    public function prefix(string $name): self
121 1
    {
122
        $newPath = clone $this;
123
124 1
        $newPath->prefix .= $name;
125
126
        return $newPath;
127
    }
128
129
    /**
130
     * Get the string value of the path
131
     *
132
     * @return string
133
     */
134 35
    public function get(): string
135
    {
136 35
        $path = $this->root.$this->path;
137
138
        if ($path === '') {
139
            return $this->prefix;
140
        }
141
142
        if (empty($this->prefix)) {
143
            return $path;
144
        }
145
146 6
        return $path.'['.$this->prefix.']';
147
    }
148 6
149
    /**
150
     * Does the current path is a prefix path ?
151
     *
152
     * @return bool
153
     */
154
    public function isPrefix(): bool
155
    {
156
        return $this->prefix !== '';
157
    }
158
159
    /**
160
     * Does the current field is a root field ?
161
     *
162
     * @return bool
163
     */
164
    public function isRootField(): bool
165
    {
166
        return $this->root !== '' && $this->path === '';
167
    }
168
169
    /**
170
     * Call ->get()
171
     *
172
     * @return string
173
     */
174
    public function __toString(): string
175
    {
176
        return $this->get();
177
    }
178
179
    /**
180
     * Get the empty path (i.e. root path)
181
     *
182
     * @return HttpFieldPath
183
     */
184
    public static function empty(): HttpFieldPath
185
    {
186
        if (self::$empty) {
187
            return self::$empty;
188
        }
189
190
        return self::$empty = new HttpFieldPath();
191
    }
192
193
    /**
194
     * Get a simple path consisting of the name
195
     *
196
     * @param string $name
197
     *
198
     * @return HttpFieldPath
199
     */
200
    public static function named(string $name): HttpFieldPath
201
    {
202
        return new HttpFieldPath($name);
203
    }
204
205
    /**
206
     * Get a path with a prefix
207
     *
208
     * @param string $prefix
209
     *
210
     * @return HttpFieldPath
211
     */
212
    public static function prefixed(string $prefix): HttpFieldPath
213
    {
214
        return new HttpFieldPath('', '', $prefix);
215
    }
216
}
217