8000 [ExpressionLanguage] Fix null-safe handling + more test cases · symfony/symfony@2b6a600 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2b6a600

Browse files
committed
[ExpressionLanguage] Fix null-safe handling + more test cases
1 parent 36897f1 commit 2b6a600

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

src/Symfony/Component/ExpressionLanguage/Node/GetAttrNode.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,26 +71,29 @@ public function evaluate(array $functions, array $values)
7171
case self::PROPERTY_CALL:
7272
$obj = $this->nodes['node']->evaluate($functions, $values);
7373
if (!\is_object($obj)) {
74+
if (is_null($obj) && $this->nodes['attribute']->isNullSafe) {
75+
return null;
76+
}
7477
throw new \RuntimeException(sprintf('Unable to get property "%s" of non-object "%s".', $this->nodes['attribute']->dump(), $this->nodes['node']->dump()));
7578
}
7679

7780
$property = $this->nodes['attribute']->attributes['value'];
7881

79-
if ($this->nodes['attribute']->isNullSafe) {
80-
return $obj->$property ?? null;
82+
if (!property_exists($obj, $property)) {
83+
throw new \RuntimeException(sprintf('Unable to get property "%s" of object "%s".', $this->nodes['attribute']->dump(), $this->nodes['node']->dump()));
8184
}
8285

8386
return $obj->$property;
8487

8588
case self::METHOD_CALL:
8689
$obj = $this->nodes['node']->evaluate($functions, $values);
8790
if (!\is_object($obj)) {
91+
if (is_null($obj) && $this->nodes['attribute']->isNullSafe) {
92+
return null;
93+
}
8894
throw new \RuntimeException(sprintf('Unable to call method "%s" of non-object "%s".', $this->nodes['attribute']->dump(), $this->nodes['node']->dump()));
8995
}
9096
if (!\is_callable($toCall = [$obj, $this->nodes['attribute']->attributes['value']])) {
91-
if ($this->nodes['attribute']->isNullSafe) {
92-
return null;
93-
}
9497
throw new \RuntimeException(sprintf('Unable to call method "%s" of object "%s".', $this->nodes['attribute']->attributes['value'], get_debug_type($obj)));
9598
}
9699

src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,37 @@ public function testRegisterAfterEval($registerCallback)
237237
$registerCallback($el);
238238
}
239239

240+
public function testBadProperty()
241+
{
242+
$this->expectException(\RuntimeException::class);
243+
$this->expectExceptionMessageMatches('/Unable to get property "\w+" of object "\w+"./');
244+
$el = new ExpressionLanguage();
245+
$el->evaluate('foo.bar', ['foo' => new \stdClass()]);
246+
}
247+
248+
public function testBadPropertyNullSafe()
249+
{
250+
$this->expectException(\RuntimeException::class);
251+
$this->expectExceptionMessageMatches('/Unable to get property "\w+" of object "\w+"./');
252+
$el = new ExpressionLanguage();
253+
$el->evaluate('foo?.bar', ['foo' => new \stdClass()]);
254+
}
255+
256+
public function testBadObjectGetProperty()
257+
{
258+
$this->expectException(\RuntimeException::class);
259+
$this->expectExceptionMessageMatches('/Unable to get property "\w+" of non-object "\w+"./');
260+
$el = new ExpressionLanguage();
261+
$el->evaluate('foo.bar', ['foo' => null]);
262+
}
263+
264+
public function testBadObjectGetPropertyNullSafe()
265+
{
266+
$el = new ExpressionLanguage();
267+
$result = $el->evaluate('foo?.bar', ['foo' => null]);
268+
$this->assertNull($result);
269+
}
270+
240271
public function testCallBadCallable()
241272
{
242273
$this->expectException(\RuntimeException::class);
@@ -245,10 +276,24 @@ public function testCallBadCallable()
245276
$el->evaluate('foo.myfunction()', ['foo' => new \stdClass()]);
246277
}
247278

248-
public function testCallBadCallableWithNullSafe()
279+
public function testCallBadCallableNullSafe()
249280
{
250281
$el = new ExpressionLanguage();
282+
$this->expectExceptionMessageMatches('/Unable to call method "\w+" of object "\w+"./');
251283
$result = $el->evaluate('foo?.myfunction()', ['foo' => new \stdClass()]);
284+
}
285+
286+
public function testBadObjectCallCallable()
287+
{
288+
$el = new ExpressionLanguage();
289+
$this->expectExceptionMessageMatches('/Unable to call method "\w+" of non-object "\w+"./');
290+
$result = $el->evaluate('foo.myfunction()', ['foo' => null]);
291+
}
292+
293+
public function testBadObjectCallCallableNullSafe()
294+
{
295+
$el = new ExpressionLanguage();
296+
$result = $el->evaluate('foo?.myfunction()', ['foo' => null]);
252297
$this->assertNull($result);
253298
}
254299

0 commit comments

Comments
 (0)
0