HttpFieldPath::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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