Skip to content

Commit

Permalink
feature #49331 [PropertyAccess] Allow escaping in PropertyPath (alanp…
Browse files Browse the repository at this point in the history
…oulain)

This PR was merged into the 6.3 branch.

Discussion
----------

[PropertyAccess] Allow escaping in PropertyPath

| Q             | A
| ------------- | ---
| Branch?       | 6.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #41845
| License       | MIT
| Doc PR        | TODO symfony/symfony-docs#...

I'm not sure if it can be considered a feature or a fix.

Currently there is no way to escape `.` and `[` when using `PropertyPath`.
It can cause issue when we want to access a "property" containing a dot (for instance a key in an array).

I tried to modify the regexp as little as possible and to handle (really) edge cases such as double escaping.

Initially I had the issue in some Behat tests where I needed to evaluate some paths in a big JSON file (OpenAPI documentation).
Some keys contain dots and I cannot test the JSON node when it's the case.

Commits
-------

d534287 feat(property-access): allow escaping in PropertyPath
  • Loading branch information
chalasr committed Feb 18, 2023
2 parents f4eaacd + d534287 commit 0900333
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/PropertyAccess/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.3
---

* Allow escaping `.` and `[` with `\` in `PropertyPath`

6.2
---

Expand Down
8 changes: 6 additions & 2 deletions src/Symfony/Component/PropertyAccess/PropertyPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function __construct(self|string $propertyPath)
$remaining = $propertyPath;

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

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

$element = preg_replace('/\\\([.[])/', '$1', $element);
if (str_ends_with($element, '\\\\')) {
$element = substr($element, 0, -1);
}
$this->elements[] = $element;

$position += \strlen($matches[1]);
$remaining = $matches[4];
$pattern = '/^(\.([^\.|\[]++)|\[([^\]]++)\])(.*)/';
$pattern = '/^(\.((?:[^\\\\.\[]|\\\\.)++)|\[([^\]]++)\])(.*)/';
}

if ('' !== $remaining) {
Expand Down
28 changes: 28 additions & 0 deletions src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,34 @@ public function testGetParentWithDot()
$this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent());
}

public function testGetElementsWithEscapedDot()
{
$propertyPath = new PropertyPath('grandpa\.parent.child');

$this->assertEquals(['grandpa.parent', 'child'], $propertyPath->getElements());
}

public function testGetElementsWithEscapedArray()
{
$propertyPath = new PropertyPath('grandpa\[parent][child]');

$this->assertEquals(['grandpa[parent]', 'child'], $propertyPath->getElements());
}

public function testGetElementsWithDoubleEscapedDot()
{
$propertyPath = new PropertyPath('grandpa\\\.par\ent.\\\child');

$this->assertEquals(['grandpa\\', 'par\ent', '\\\child'], $propertyPath->getElements());
}

public function testGetElementsWithDoubleEscapedArray()
{
$propertyPath = new PropertyPath('grandpa\\\[par\ent][\\\child]');

$this->assertEquals(['grandpa\\', 'par\ent', '\\\child'], $propertyPath->getElements());
}

public function testGetParentWithIndex()
{
$propertyPath = new PropertyPath('grandpa.parent[child]');
Expand Down

0 comments on commit 0900333

Please sign in to comment.