Skip to content

Commit cbe18c6

Browse files
authored
Merge pull request #24 from colinodell/slash-delimiters-hard-coded
Allow slash-delimited paths (hard coded)
2 parents 5b2ba69 + 507a699 commit cbe18c6

File tree

2 files changed

+61
-38
lines changed

2 files changed

+61
-38
lines changed

src/Data.php

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
*/
2121
class Data implements DataInterface, ArrayAccess
2222
{
23+
private const DELIMITERS = ['.', '/'];
24+
2325
/**
2426
* Internal representation of data data
2527
*
@@ -42,12 +44,8 @@ public function __construct(array $data = [])
4244
*/
4345
public function append(string $key, $value = null): void
4446
{
45-
if (0 == strlen($key)) {
46-
throw new InvalidPathException("Key cannot be an empty string");
47-
}
48-
4947
$currentValue =& $this->data;
50-
$keyPath = explode('.', $key);
48+
$keyPath = $this->keyToPathArray($key);
5149

5250
if (1 == count($keyPath)) {
5351
if (!isset($currentValue[$key])) {
@@ -88,12 +86,8 @@ public function append(string $key, $value = null): void
8886
*/
8987
public function set(string $key, $value = null): void
9088
{
91-
if (0 == strlen($key)) {
92-
throw new InvalidPathException("Key cannot be an empty string");
93-
}
94-
9589
$currentValue =& $this->data;
96-
$keyPath = explode('.', $key);
90+
$keyPath = $this->keyToPathArray($key);
9791

9892
if (1 == count($keyPath)) {
9993
$currentValue[$key] = $value;
@@ -120,12 +114,8 @@ public function set(string $key, $value = null): void
120114
*/
121115
public function remove(string $key): void
122116
{
123-
if (0 == strlen($key)) {
124-
throw new InvalidPathException("Key cannot be an empty string");
125-
}
126-
127117
$currentValue =& $this->data;
128-
$keyPath = explode('.', $key);
118+
$keyPath = $this->keyToPathArray($key);
129119

130120
if (1 == count($keyPath)) {
131121
unset($currentValue[$key]);
@@ -152,7 +142,7 @@ public function remove(string $key): void
152142
public function get(string $key, $default = null)
153143
{
154144
$currentValue = $this->data;
155-
$keyPath = explode('.', $key);
145+
$keyPath = $this->keyToPathArray($key);
156146

157147
for ($i = 0; $i < count($keyPath); $i++) {
158148
$currentKey = $keyPath[$i];
@@ -176,7 +166,7 @@ public function get(string $key, $default = null)
176166
public function has(string $key): bool
177167
{
178168
$currentValue = &$this->data;
179-
$keyPath = explode('.', $key);
169+
$keyPath = $this->keyToPathArray($key);
180170

181171
for ($i = 0; $i < count($keyPath); $i++) {
182172
$currentKey = $keyPath[$i];
@@ -266,4 +256,22 @@ public function offsetUnset($key)
266256
{
267257
$this->remove($key);
268258
}
259+
260+
/**
261+
* @return string[]
262+
*
263+
* @psalm-return non-empty-list<string>
264+
*
265+
* @psalm-pure
266+
*/
267+
protected function keyToPathArray(string $path): array
268+
{
269+
if (\strlen($path) === 0) {
270+
throw new InvalidPathException('Path cannot be an empty string');
271+
}
272+
273+
$path = \str_replace(self::DELIMITERS, '.', $path);
274+
275+
return \explode('.', $path);
276+
}
269277
}

tests/DataTest.php

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,21 @@ protected function runSampleDataTests(DataInterface $data)
4949
{
5050
$this->assertEquals('A', $data->get('a'));
5151
$this->assertEquals('B', $data->get('b.b'));
52+
$this->assertEquals('B', $data->get('b/b'));
5253
$this->assertEquals(['C1', 'C2', 'C3'], $data->get('b.c'));
54+
$this->assertEquals(['C1', 'C2', 'C3'], $data->get('b/c'));
5355
$this->assertEquals('D3', $data->get('b.d.d3'));
56+
$this->assertEquals('D3', $data->get('b/d/d3'));
5457
$this->assertEquals(['c1', 'c2', 'c3'], $data->get('c'));
55-
$this->assertNull($data->get('foo'), 'Foo should not exist');
56-
$this->assertNull($data->get('f.g.h.i'));
58+
$this->assertNull($data->get('foo', null), 'Foo should not exist');
59+
$this->assertNull($data->get('f.g.h.i', null));
60+
$this->assertNull($data->get('f/g/h/i', null));
5761
$this->assertEquals($data->get('foo', 'default-value-1'), 'default-value-1', 'Return default value');
5862
$this->assertEquals($data->get('f.g.h.i', 'default-value-2'), 'default-value-2');
63+
$this->assertEquals($data->get('f/g/h/i', 'default-value-2'), 'default-value-2');
64+
65+
$this->expectException(InvalidPathException::class);
66+
$data->get('', 'broken');
5967
}
6068

6169
public function testAppend()
@@ -65,12 +73,12 @@ public function testAppend()
6573
$data->append('a', 'B');
6674
$data->append('c', 'c4');
6775
$data->append('b.c', 'C4');
68-
$data->append('b.d.d3', 'D3b');
76+
$data->append('b/d/d3', 'D3b');
6977
$data->append('b.d.d4', 'D');
7078
$data->append('e', 'E');
71-
$data->append('f.a', 'b');
79+
$data->append('f/a', 'b');
7280
$data->append('h.i', 'I2');
73-
$data->append('i.k.l', 'L');
81+
$data->append('i/k/l', 'L');
7482

7583
$this->assertEquals(['A', 'B'], $data->get('a'));
7684
$this->assertEquals(['c1', 'c2', 'c3', 'c4'], $data->get('c'));
@@ -91,18 +99,18 @@ public function testSet()
9199
{
92100
$data = new Data();
93101

94-
$this->assertNull($data->get('a'));
95-
$this->assertNull($data->get('b.c'));
96-
$this->assertNull($data->get('d.e'));
102+
$this->assertNull($data->get('a', null));
103+
$this->assertNull($data->get('b/c', null));
104+
$this->assertNull($data->get('d.e', null));
97105

98106
$data->set('a', 'A');
99-
$data->set('b.c', 'C');
107+
$data->set('b/c', 'C');
100108
$data->set('d.e', ['f' => 'F', 'g' => 'G']);
101109

102110
$this->assertEquals('A', $data->get('a'));
103111
$this->assertEquals(['c' => 'C'], $data->get('b'));
104112
$this->assertEquals('C', $data->get('b.c'));
105-
$this->assertEquals('F', $data->get('d.e.f'));
113+
$this->assertEquals('F', $data->get('d/e/f'));
106114
$this->assertEquals(['e' => ['f' => 'F', 'g' => 'G']], $data->get('d'));
107115

108116
$this->expectException(InvalidPathException::class);
@@ -127,13 +135,13 @@ public function testRemove()
127135

128136
$data->remove('a');
129137
$data->remove('b.c');
130-
$data->remove('b.d.d3');
138+
$data->remove('b/d/d3');
131139
$data->remove('d');
132140
$data->remove('d.e.f');
133141
$data->remove('empty.path');
134142

135143
$this->assertNull($data->get('a'));
136-
$this->assertNull($data->get('b.c'));
144+
$this->assertNull($data->get('b/c'));
137145
$this->assertNull($data->get('b.d.d3'));
138146
$this->assertNull(null);
139147
$this->assertEquals('D2', $data->get('b.d.d2'));
@@ -155,16 +163,19 @@ public function testHas()
155163
$data = new Data($this->getSampleData());
156164

157165
foreach (
158-
['a', 'i', 'b.d', 'f.g.h', 'h.i', 'b.d.d1'] as $existentKey
166+
['a', 'i', 'b.d', 'b/d', 'f.g.h', 'f/g/h', 'h.i', 'h/i', 'b.d.d1', 'b/d/d1'] as $existentKey
159167
) {
160168
$this->assertTrue($data->has($existentKey));
161169
}
162170

163171
foreach (
164-
['p', 'b.b1', 'b.c.C1', 'h.i.I', 'b.d.d1.D1'] as $notExistentKey
172+
['p', 'b.b1', 'b/b1', 'b.c.C1', 'b/c/C1', 'h.i.I', 'h/i/I', 'b.d.d1.D1', 'b/d/d1/D1'] as $notExistentKey
165173
) {
166174
$this->assertFalse($data->has($notExistentKey));
167175
}
176+
177+
$this->expectException(InvalidPathException::class);
178+
$data->has('', 'broken');
168179
}
169180

170181
public function testGetData()
@@ -212,13 +223,13 @@ public function testOffsetExists()
212223
$data = new Data($this->getSampleData());
213224

214225
foreach (
215-
['a', 'i', 'b.d', 'f.g.h', 'h.i', 'b.d.d1'] as $existentKey
226+
['a', 'i', 'b.d', 'b/d', 'f.g.h', 'f/g/h', 'h.i', 'h/i', 'b.d.d1', 'b/d/d1'] as $existentKey
216227
) {
217228
$this->assertTrue(isset($data[$existentKey]));
218229
}
219230

220231
foreach (
221-
['p', 'b.b1', 'b.c.C1', 'h.i.I', 'b.d.d1.D1'] as $notExistentKey
232+
['p', 'b.b1', 'b/b1', 'b.c.C1', 'b/c/C1', 'h.i.I', 'h/i/I', 'b.d.d1.D1', 'b/d/d1/D1'] as $notExistentKey
222233
) {
223234
$this->assertFalse(isset($data[$notExistentKey]));
224235
}
@@ -236,11 +247,15 @@ public function testOffsetGet()
236247

237248
$this->assertEquals('A', $data['a']);
238249
$this->assertEquals('B', $data['b.b']);
250+
$this->assertEquals('B', $data['b/b']);
239251
$this->assertEquals(['C1', 'C2', 'C3'], $data['b.c']);
252+
$this->assertEquals(['C1', 'C2', 'C3'], $data['b/c']);
240253
$this->assertEquals('D3', $data['b.d.d3']);
254+
$this->assertEquals('D3', $data['b/d/d3']);
241255
$this->assertEquals(['c1', 'c2', 'c3'], $data['c']);
242256
$this->assertNull($data['foo'], 'Foo should not exist');
243257
$this->assertNull($data['f.g.h.i']);
258+
$this->assertNull($data['f/g/h/i']);
244259
}
245260

246261
public function testOffsetSet()
@@ -251,14 +266,14 @@ public function testOffsetSet()
251266
$this->assertNull($data['b.c']);
252267
$this->assertNull($data['d.e']);
253268

254-
$data['a'] = 'A';
255-
$data['b.c'] = 'C';
269+
$data['a'] = 'A';
270+
$data['b/c'] = 'C';
256271
$data['d.e'] = ['f' => 'F', 'g' => 'G'];
257272

258273
$this->assertEquals('A', $data['a']);
259274
$this->assertEquals(['c' => 'C'], $data['b']);
260275
$this->assertEquals('C', $data['b.c']);
261-
$this->assertEquals('F', $data['d.e.f']);
276+
$this->assertEquals('F', $data['d/e/f']);
262277
$this->assertEquals(['e' => ['f' => 'F', 'g' => 'G']], $data['d']);
263278

264279
$this->expectException(InvalidPathException::class);
@@ -271,15 +286,15 @@ public function testOffsetUnset()
271286
$data = new Data($this->getSampleData());
272287

273288
unset($data['a']);
274-
unset($data['b.c']);
289+
unset($data['b/c']);
275290
unset($data['b.d.d3']);
276291
unset($data['d']);
277292
unset($data['d.e.f']);
278293
unset($data['empty.path']);
279294

280295
$this->assertNull($data['a']);
281296
$this->assertNull($data['b.c']);
282-
$this->assertNull($data['b.d.d3']);
297+
$this->assertNull($data['b/d/d3']);
283298
$this->assertNull(null);
284299
$this->assertEquals('D2', $data['b.d.d2']);
285300

0 commit comments

Comments
 (0)