Skip to content

Commit 9b6013a

Browse files
committed
feat(property-access): allow escaping in PropertyPath
1 parent b7b2eb8 commit 9b6013a

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.3
5+
---
6+
7+
* Allow escaping `.` and `[` with `\` in `PropertyPath`
8+
49
6.2
510
---
611

PropertyPath.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function __construct(self|string $propertyPath)
9595
$remaining = $propertyPath;
9696

9797
// first element is evaluated differently - no leading dot for properties
98-
$pattern = '/^(([^\.\[]++)|\[([^\]]++)\])(.*)/';
98+
$pattern = '/^(((?:[^\\\\.\[]|\\\\.)++)|\[([^\]]++)\])(.*)/';
9999

100100
while (preg_match($pattern, $remaining, $matches)) {
101101
if ('' !== $matches[2]) {
@@ -114,11 +114,15 @@ public function __construct(self|string $propertyPath)
114114
$this->isNullSafe[] = false;
115115
}
116116

117+
$element = preg_replace('/\\\([.[])/', '$1', $element);
118+
if (str_ends_with($element, '\\\\')) {
119+
$element = substr($element, 0, -1);
120+
}
117121
$this->elements[] = $element;
118122

119123
$position += \strlen($matches[1]);
120124
$remaining = $matches[4];
121-
$pattern = '/^(\.([^\.|\[]++)|\[([^\]]++)\])(.*)/';
125+
$pattern = '/^(\.((?:[^\\\\.\[]|\\\\.)++)|\[([^\]]++)\])(.*)/';
122126
}
123127

124128
if ('' !== $remaining) {

Tests/PropertyPathTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ public function testGetParentWithDot()
7878
$this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent());
7979
}
8080

81+
public function testGetElementsWithEscapedDot()
82+
{
83+
$propertyPath = new PropertyPath('grandpa\.parent.child');
84+
85+
$this->assertEquals(['grandpa.parent', 'child'], $propertyPath->getElements());
86+
}
87+
88+
public function testGetElementsWithEscapedArray()
89+
{
90+
$propertyPath = new PropertyPath('grandpa\[parent][child]');
91+
92+
$this->assertEquals(['grandpa[parent]', 'child'], $propertyPath->getElements());
93+
}
94+
95+
public function testGetElementsWithDoubleEscapedDot()
96+
{
97+
$propertyPath = new PropertyPath('grandpa\\\.par\ent.\\\child');
98+
99+
$this->assertEquals(['grandpa\\', 'par\ent', '\\\child'], $propertyPath->getElements());
100+
}
101+
102+
public function testGetElementsWithDoubleEscapedArray()
103+
{
104+
$propertyPath = new PropertyPath('grandpa\\\[par\ent][\\\child]');
105+
106+
$this->assertEquals(['grandpa\\', 'par\ent', '\\\child'], $propertyPath->getElements());
107+
}
108+
81109
public function testGetParentWithIndex()
82110
{
83111
$propertyPath = new PropertyPath('grandpa.parent[child]');

0 commit comments

Comments
 (0)