diff --git a/README.md b/README.md
index d72e46a..8f75b0d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
Obelix
diff --git a/composer.json b/composer.json
index b2c2de8..a875f3b 100644
--- a/composer.json
+++ b/composer.json
@@ -32,5 +32,11 @@
},
"archive": {
"exclude": ["obelix.jpg"]
+ },
+ "scripts": {
+ "check": [
+ "phpunit --stop-on-fail --coverage-text",
+ "phpstan analyse src --level 8"
+ ]
}
}
diff --git a/src/Dot.php b/src/Dot.php
index 9ac0bd7..3ac174a 100644
--- a/src/Dot.php
+++ b/src/Dot.php
@@ -65,14 +65,13 @@ public function get(string $path, $default = null): ResultSet
return new ResultSet(...self::$cache[$path]);
}
- $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->items), RecursiveIteratorIterator::SELF_FIRST);
-
$pathway = [];
$flatArray = null;
$segments = (array) explode($this->delimiter, $path);
$countSegments = count($segments);
- $countWildcards = count(array_filter($segments, fn($x) => $x === $this->wildcard));
+
+ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->items), RecursiveIteratorIterator::SELF_FIRST);
foreach ($it as $key => $value) {
$pathway[$it->getDepth()] = $key;
@@ -81,7 +80,7 @@ public function get(string $path, $default = null): ResultSet
continue;
}
- if (count(array_diff($segments, $pathway)) === $countWildcards) {
+ if ($this->isUserPathEqualsRealPath($segments, $pathway)) {
$flatArray[
implode($this->delimiter, array_slice($pathway, 0, $it->getDepth() + 1))
] = $value;
@@ -100,6 +99,42 @@ public function get(string $path, $default = null): ResultSet
return new ResultSet($value, $flatArray ?? []);
}
+ /**
+ * @param array $user
+ * @param array $real
+ * @return bool
+ */
+ private function isUserPathEqualsRealPath(array $user, array $real): bool
+ {
+ if ($user === $real) {
+ return true;
+ }
+
+ $i = 0;
+ $equals = false;
+
+ foreach ($user as $item) {
+ $val = $real[$i] ?? false;
+
+ // to work with integer indexes in string path (for cases like "foo.0")
+ if (ctype_digit($item)) {
+ $item = (int) $item;
+ }
+
+ if ($val === $item) {
+ $equals = true;
+ } elseif ($item === $this->wildcard) {
+ $equals = true;
+ } else {
+ return false;
+ }
+
+ $i++;
+ }
+
+ return $equals;
+ }
+
/**
* @return array
*/
diff --git a/tests/DotTest.php b/tests/DotTest.php
index 7b5ed21..574942a 100644
--- a/tests/DotTest.php
+++ b/tests/DotTest.php
@@ -384,4 +384,151 @@ public function testGetItemWithWildcardAndAssociativeArray()
'foo.bar.key2' => 2,
], $dot->get('foo.*.*')->getMap());
}
+
+ public function testGetItemWhenSecondKeyIsNotUniqueInSubArrays()
+ {
+ $array = [
+ 'server' => [
+ 'foo' => [
+ 'headers' => [
+ 'omg' => 'it'
+ ],
+ ],
+ 'prerender' => [
+ 'headers' => [],
+ ],
+ 'logger' => [
+ 'enabled' => false,
+ 'level' => 'info',
+ ],
+ 'headers' => [
+ 'foo' => 'bar',
+ ],
+ ],
+ ];
+
+ $dot = new Obelix\Dot($array);
+
+ $this->assertSame([
+ 'foo' => 'bar'
+ ], $dot->get('server.headers')->getValue());
+
+ $this->assertSame([
+ 'server.headers' => [
+ 'foo' => 'bar'
+ ]
+ ], $dot->get('server.headers')->getMap());
+ }
+
+ public function testWhenALotOfManyKeysAndValuesAreSameAkaHardestTest()
+ {
+ $array = [
+ 'foo' => [
+ null,
+ 'foo' => 'foo',
+ 'bar' => 'bar',
+ 'baz' => [
+ 'foo' => 'bar',
+ 'bar' => 'foo',
+ 'baz' => [
+ 'foo',
+ 'bar',
+ 'baz' => [
+ 'baz', 'foo', 'bar', 0
+ ]
+ ],
+ 'acme' => [
+ 'foo' => -10001,
+ 'bar',
+ 'baz' => [
+ 'baz', 'acme'
+ ]
+ ],
+ [],
+ false,
+ null
+ ],
+ 'faa' => [
+ 'foo' => 'bar',
+ 'bar' => 'foo',
+ 'baz' => [
+ 'faa',
+ 'baa',
+ 'baz' => [
+ 'baz', 'foo', 'bar', 1
+ ]
+ ],
+ 'acme' => [
+ 'foo',
+ 'bar',
+ 'baz' => [
+ 'baz', 'acme', 999
+ ]
+ ],
+ true,
+ [],
+ new \stdClass()
+ ]
+ ],
+ 'bar' => 1,
+ 'acme' => [
+ 'foo',
+ 'bar',
+ 'baz' => [
+ 'baz'
+ ]
+ ],
+ 1,
+ 0
+ ];
+
+ $dot = new Obelix\Dot($array);
+
+ $result = $dot->get('foo.0');
+ $this->assertSame(null, $result->getValue());
+ $this->assertSame(['foo.0' => null], $result->getMap());
+
+ $result = $dot->get('foo.baz.baz.0');
+ $this->assertSame('foo', $result->getValue());
+ $this->assertSame(['foo.baz.baz.0' => 'foo'], $result->getMap());
+
+ $expected = [
+ 'foo' => -10001,
+ 'bar',
+ 'baz' => [
+ 'baz', 'acme'
+ ]
+ ];
+ $result = $dot->get('foo.baz.acme');
+ $this->assertSame($expected, $result->getValue());
+ $this->assertSame(['foo.baz.acme' => $expected], $result->getMap());
+
+ $result = $dot->get('foo.faa.2');
+ $this->assertInstanceOf(\stdClass::class, $result->getValue());
+ $this->assertSame($array['foo']['faa'][2], $result->getValue());
+ $this->assertSame(['foo.faa.2' => $array['foo']['faa'][2]], $result->getMap());
+
+ $result = $dot->get('foo.faa.0');
+ $this->assertSame(true, $result->getValue());
+ $this->assertSame(['foo.faa.0' => true], $result->getMap());
+
+ $expected = [
+ 'baz', 'acme', 999
+ ];
+ $result = $dot->get('foo.faa.acme.baz');
+ $this->assertSame($expected, $result->getValue());
+ $this->assertSame(['foo.faa.acme.baz' => $expected], $result->getMap());
+
+ $expected = [
+ 'baz', 'foo', 'bar', 0
+ ];
+ $result = $dot->get('foo.baz.baz.baz.*');
+ $this->assertSame($expected, $result->getValue());
+ $this->assertSame([
+ 'foo.baz.baz.baz.0' => 'baz',
+ 'foo.baz.baz.baz.1' => 'foo',
+ 'foo.baz.baz.baz.2' => 'bar',
+ 'foo.baz.baz.baz.3' => 0,
+ ], $result->getMap());
+ }
}