From 91ab85c607530676940b1d31b451b57f868d7e03 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 14:19:06 +0200 Subject: [PATCH 1/9] Errors from symfony property accessor now result in PropertyNotAccessibleException --- .../PurgatoryPropertyAccessor.php | 17 +++- .../PropertyAccess/Fixtures/Foo.php | 1 + .../PurgatoryPropertyAccessorTest.php | 95 +++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php index e663ab69..bb7ad124 100644 --- a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php +++ b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php @@ -4,6 +4,8 @@ namespace Sofascore\PurgatoryBundle\RouteProvider\PropertyAccess; +use InvalidArgumentException; +use Sofascore\PurgatoryBundle\Exception\PropertyNotAccessibleException; use Sofascore\PurgatoryBundle\Exception\ValueNotIterableException; use Symfony\Component\PropertyAccess\Exception\AccessException; use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; @@ -25,17 +27,28 @@ public function __construct( /** * @param object|array $objectOrArray * @param string|PropertyPathInterface $propertyPath + * + * @throws PropertyNotAccessibleException + * @throws ValueNotIterableException */ public function getValue($objectOrArray, $propertyPath): mixed { if (!str_contains((string) $propertyPath, self::DELIMITER)) { - return $this->propertyAccessor->getValue($objectOrArray, $propertyPath); + try{ + return $this->propertyAccessor->getValue($objectOrArray, $propertyPath); + } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { + throw new PropertyNotAccessibleException($objectOrArray::class, (string)$propertyPath); + } } /** @var array{0: string, 1: string} $propertyPathParts */ $propertyPathParts = explode(separator: self::DELIMITER, string: (string) $propertyPath, limit: 2); - $collection = $this->propertyAccessor->getValue($objectOrArray, $propertyPathParts[0]); + try{ + $collection = $this->propertyAccessor->getValue($objectOrArray, $propertyPathParts[0]); + } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { + throw new PropertyNotAccessibleException($objectOrArray::class, $propertyPathParts[0]); + } if (!is_iterable($collection)) { throw new ValueNotIterableException($collection, $propertyPathParts[0]); diff --git a/tests/RouteProvider/PropertyAccess/Fixtures/Foo.php b/tests/RouteProvider/PropertyAccess/Fixtures/Foo.php index ad52af1d..4ae47224 100644 --- a/tests/RouteProvider/PropertyAccess/Fixtures/Foo.php +++ b/tests/RouteProvider/PropertyAccess/Fixtures/Foo.php @@ -11,6 +11,7 @@ class Foo public function __construct( public readonly int $id, public readonly Collection $children, + private readonly ?string $privateProperty = 'value', ) { } diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index 690dc189..51057a04 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -8,6 +8,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; +use Sofascore\PurgatoryBundle\Exception\PropertyNotAccessibleException; use Sofascore\PurgatoryBundle\Exception\ValueNotIterableException; use Sofascore\PurgatoryBundle\RouteProvider\PropertyAccess\PurgatoryPropertyAccessor; use Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo; @@ -143,4 +144,98 @@ public function testNotTraversable(): void propertyPath: 'id[*].id', ); } + + public function testPropertyNotAccessible(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'privateProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'privateProperty', + ); + } + + public function testTraversableChildPropertyNotAccessible(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'privateProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection( + [ + new Foo( + id: 1, + children: new ArrayCollection([]), + ), + ] + ), + ), + propertyPath: 'children[*].privateProperty', + ); + } + + public function testPropertyNotExist(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'nonExistentProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'nonExistentProperty', + ); + } + + public function testTraversableChildPropertyNotExist(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'nonExistentProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection( + [ + new Foo( + id: 1, + children: new ArrayCollection([]), + ), + ] + ), + ), + propertyPath: 'children[*].nonExistentProperty', + ); + } } From 3ba903050ba8bdb8e8cf26e5488915d8cb9cea01 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 14:48:32 +0200 Subject: [PATCH 2/9] Static code analysis fix --- .../PropertyAccess/PurgatoryPropertyAccessor.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php index bb7ad124..574aea29 100644 --- a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php +++ b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php @@ -37,7 +37,10 @@ public function getValue($objectOrArray, $propertyPath): mixed try{ return $this->propertyAccessor->getValue($objectOrArray, $propertyPath); } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { - throw new PropertyNotAccessibleException($objectOrArray::class, (string)$propertyPath); + throw new PropertyNotAccessibleException( + \is_array($objectOrArray) ? 'array' : $objectOrArray::class, + (string)$propertyPath + ); } } @@ -47,7 +50,10 @@ public function getValue($objectOrArray, $propertyPath): mixed try{ $collection = $this->propertyAccessor->getValue($objectOrArray, $propertyPathParts[0]); } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { - throw new PropertyNotAccessibleException($objectOrArray::class, $propertyPathParts[0]); + throw new PropertyNotAccessibleException( + \is_array($objectOrArray) ? 'array' : $objectOrArray::class, + $propertyPathParts[0] + ); } if (!is_iterable($collection)) { From e42767286c46ffd0440e7f88a3b6f59704293880 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 14:51:13 +0200 Subject: [PATCH 3/9] Lint --- .../PurgatoryPropertyAccessor.php | 19 ++++++------ .../PurgatoryPropertyAccessorTest.php | 30 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php index 574aea29..eea14c0a 100644 --- a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php +++ b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php @@ -4,7 +4,6 @@ namespace Sofascore\PurgatoryBundle\RouteProvider\PropertyAccess; -use InvalidArgumentException; use Sofascore\PurgatoryBundle\Exception\PropertyNotAccessibleException; use Sofascore\PurgatoryBundle\Exception\ValueNotIterableException; use Symfony\Component\PropertyAccess\Exception\AccessException; @@ -27,19 +26,19 @@ public function __construct( /** * @param object|array $objectOrArray * @param string|PropertyPathInterface $propertyPath - * + * * @throws PropertyNotAccessibleException * @throws ValueNotIterableException */ public function getValue($objectOrArray, $propertyPath): mixed { if (!str_contains((string) $propertyPath, self::DELIMITER)) { - try{ + try { return $this->propertyAccessor->getValue($objectOrArray, $propertyPath); - } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { + } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException) { throw new PropertyNotAccessibleException( - \is_array($objectOrArray) ? 'array' : $objectOrArray::class, - (string)$propertyPath + \is_array($objectOrArray) ? 'array' : $objectOrArray::class, + (string) $propertyPath, ); } } @@ -47,12 +46,12 @@ public function getValue($objectOrArray, $propertyPath): mixed /** @var array{0: string, 1: string} $propertyPathParts */ $propertyPathParts = explode(separator: self::DELIMITER, string: (string) $propertyPath, limit: 2); - try{ + try { $collection = $this->propertyAccessor->getValue($objectOrArray, $propertyPathParts[0]); - } catch (InvalidArgumentException|AccessException|UnexpectedTypeException) { + } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException) { throw new PropertyNotAccessibleException( - \is_array($objectOrArray) ? 'array' : $objectOrArray::class, - $propertyPathParts[0] + \is_array($objectOrArray) ? 'array' : $objectOrArray::class, + $propertyPathParts[0], ); } diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index 51057a04..c534eb87 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -149,9 +149,9 @@ public function testPropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); $this->expectExceptionMessage( - sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, 'privateProperty', ), ); @@ -169,9 +169,9 @@ public function testTraversableChildPropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); $this->expectExceptionMessage( - sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, 'privateProperty', ), ); @@ -185,7 +185,7 @@ public function testTraversableChildPropertyNotAccessible(): void id: 1, children: new ArrayCollection([]), ), - ] + ], ), ), propertyPath: 'children[*].privateProperty', @@ -196,9 +196,9 @@ public function testPropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); $this->expectExceptionMessage( - sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, 'nonExistentProperty', ), ); @@ -216,9 +216,9 @@ public function testTraversableChildPropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); $this->expectExceptionMessage( - sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, 'nonExistentProperty', ), ); @@ -232,10 +232,10 @@ public function testTraversableChildPropertyNotExist(): void id: 1, children: new ArrayCollection([]), ), - ] + ], ), ), propertyPath: 'children[*].nonExistentProperty', ); - } + } } From 3dfd226eb8bffef1a442e927d42657be67829ca1 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 14:56:54 +0200 Subject: [PATCH 4/9] Static code analysis fix --- .../PropertyAccess/PurgatoryPropertyAccessor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php index eea14c0a..a5d82628 100644 --- a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php +++ b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php @@ -78,6 +78,8 @@ public function getValue($objectOrArray, $propertyPath): mixed /** * @param object|array $objectOrArray * @param string|PropertyPathInterface $propertyPath + * + * @param-out object|array $objectOrArray */ public function setValue(&$objectOrArray, $propertyPath, mixed $value): void { @@ -107,7 +109,7 @@ public function isReadable($objectOrArray, $propertyPath): bool $this->getValue($objectOrArray, $propertyPath); return true; - } catch (AccessException|UnexpectedTypeException) { + } catch (PropertyNotAccessibleException) { return false; } } From a9a5ba30ec7f814e97a00296021e2c411fe91da2 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 15:02:09 +0200 Subject: [PATCH 5/9] Improve test coverage --- .../PurgatoryPropertyAccessorTest.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index c534eb87..c8afc8c7 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -165,6 +165,26 @@ public function testPropertyNotAccessible(): void ); } + public function testTraversablePropertyNotAccessible(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'privateProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'privateProperty[*].values', + ); + } + public function testTraversableChildPropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); @@ -212,6 +232,26 @@ public function testPropertyNotExist(): void ); } + public function testTraversablePropertyNotExist(): void + { + $this->expectException(PropertyNotAccessibleException::class); + $this->expectExceptionMessage( + \sprintf( + 'Unable to create a getter for property "%s::%s".', + Foo::class, + 'nonExistentProperty', + ), + ); + + $this->purgatoryPropertyAccessor->getValue( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'nonExistentProperty[*].values', + ); + } + public function testTraversableChildPropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); From f9318800d6a3d4b57a26df825a71fdaf24709714 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 15:09:03 +0200 Subject: [PATCH 6/9] Improve test coverage --- .../PurgatoryPropertyAccessorTest.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index c8afc8c7..d0dc2379 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -131,6 +131,28 @@ public static function traversableProvider(): iterable ]; } + public function testReadPathPropertyNotExist(): void + { + self::assertFalse($this->purgatoryPropertyAccessor->isReadable( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'nonExistentProperty', + )); + } + + public function testReadPathPropertyNotAccessible(): void + { + self::assertFalse($this->purgatoryPropertyAccessor->isReadable( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([]), + ), + propertyPath: 'privateProperty', + )); + } + public function testNotTraversable(): void { $this->expectException(ValueNotIterableException::class); From ca270259acbaa17844393caca812886afd1241b1 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Tue, 1 Jul 2025 15:14:14 +0200 Subject: [PATCH 7/9] Improve test coverage --- .../PurgatoryPropertyAccessorTest.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index d0dc2379..ffc7324b 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -153,6 +153,38 @@ public function testReadPathPropertyNotAccessible(): void )); } + public function testReadTraversableChildPropertyNotExist(): void + { + self::assertFalse($this->purgatoryPropertyAccessor->isReadable( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([ + new Foo( + id: 1, + children: new ArrayCollection([]), + ), + ]), + ), + propertyPath: 'children[*].nonExistentProperty', + )); + } + + public function testReadTraversableChildPropertyNotAccessible(): void + { + self::assertFalse($this->purgatoryPropertyAccessor->isReadable( + objectOrArray: new Foo( + id: 1, + children: new ArrayCollection([ + new Foo( + id: 1, + children: new ArrayCollection([]), + ), + ]), + ), + propertyPath: 'children[*].privateProperty', + )); + } + public function testNotTraversable(): void { $this->expectException(ValueNotIterableException::class); From 7af442d02922e911919fcb0dcf6d128fe31b1a24 Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Wed, 27 Aug 2025 15:32:01 +0200 Subject: [PATCH 8/9] Added previous throwable to exception --- .../PropertyNotAccessibleException.php | 2 + .../PurgatoryPropertyAccessor.php | 6 +- .../PurgatoryPropertyAccessorTest.php | 73 ++++++++++--------- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/Exception/PropertyNotAccessibleException.php b/src/Exception/PropertyNotAccessibleException.php index 9a62f7c9..f088f05f 100644 --- a/src/Exception/PropertyNotAccessibleException.php +++ b/src/Exception/PropertyNotAccessibleException.php @@ -11,9 +11,11 @@ final class PropertyNotAccessibleException extends RuntimeException public function __construct( public readonly string $class, public readonly string $property, + public readonly \Throwable $previous, ) { parent::__construct( message: \sprintf(self::MESSAGE, $class, $property), + previous: $previous, ); } } diff --git a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php index a5d82628..39704d90 100644 --- a/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php +++ b/src/RouteProvider/PropertyAccess/PurgatoryPropertyAccessor.php @@ -35,10 +35,11 @@ public function getValue($objectOrArray, $propertyPath): mixed if (!str_contains((string) $propertyPath, self::DELIMITER)) { try { return $this->propertyAccessor->getValue($objectOrArray, $propertyPath); - } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException) { + } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException $exception) { throw new PropertyNotAccessibleException( \is_array($objectOrArray) ? 'array' : $objectOrArray::class, (string) $propertyPath, + $exception, ); } } @@ -48,10 +49,11 @@ public function getValue($objectOrArray, $propertyPath): mixed try { $collection = $this->propertyAccessor->getValue($objectOrArray, $propertyPathParts[0]); - } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException) { + } catch (\InvalidArgumentException|AccessException|UnexpectedTypeException $exception) { throw new PropertyNotAccessibleException( \is_array($objectOrArray) ? 'array' : $objectOrArray::class, $propertyPathParts[0], + $exception, ); } diff --git a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php index ffc7324b..ee7e29f5 100644 --- a/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php +++ b/tests/RouteProvider/PropertyAccess/PurgatoryPropertyAccessorTest.php @@ -12,6 +12,7 @@ use Sofascore\PurgatoryBundle\Exception\ValueNotIterableException; use Sofascore\PurgatoryBundle\RouteProvider\PropertyAccess\PurgatoryPropertyAccessor; use Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; #[CoversClass(PurgatoryPropertyAccessor::class)] @@ -202,13 +203,13 @@ public function testNotTraversable(): void public function testPropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'privateProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'privateProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "privateProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( @@ -222,13 +223,13 @@ public function testPropertyNotAccessible(): void public function testTraversablePropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'privateProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'privateProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "privateProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( @@ -242,13 +243,13 @@ public function testTraversablePropertyNotAccessible(): void public function testTraversableChildPropertyNotAccessible(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'privateProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'privateProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "privateProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( @@ -269,13 +270,13 @@ public function testTraversableChildPropertyNotAccessible(): void public function testPropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'nonExistentProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'nonExistentProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "nonExistentProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( @@ -289,13 +290,13 @@ public function testPropertyNotExist(): void public function testTraversablePropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'nonExistentProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'nonExistentProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "nonExistentProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( @@ -309,13 +310,13 @@ public function testTraversablePropertyNotExist(): void public function testTraversableChildPropertyNotExist(): void { $this->expectException(PropertyNotAccessibleException::class); - $this->expectExceptionMessage( - \sprintf( - 'Unable to create a getter for property "%s::%s".', - Foo::class, - 'nonExistentProperty', + $this->expectExceptionObject(new PropertyNotAccessibleException( + class: Foo::class, + property: 'nonExistentProperty', + previous: new NoSuchPropertyException( + message: 'Can\'t get a way to read the property "nonExistentProperty" in class "Sofascore\PurgatoryBundle\Tests\RouteProvider\PropertyAccess\Fixtures\Foo".', ), - ); + )); $this->purgatoryPropertyAccessor->getValue( objectOrArray: new Foo( From 76eca5b07c9de1fa396dd036153e6b51d8a745aa Mon Sep 17 00:00:00 2001 From: "kresimir.lezaic" Date: Wed, 27 Aug 2025 15:35:47 +0200 Subject: [PATCH 9/9] Previous should be optional --- src/Exception/PropertyNotAccessibleException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/PropertyNotAccessibleException.php b/src/Exception/PropertyNotAccessibleException.php index f088f05f..8080bc60 100644 --- a/src/Exception/PropertyNotAccessibleException.php +++ b/src/Exception/PropertyNotAccessibleException.php @@ -11,7 +11,7 @@ final class PropertyNotAccessibleException extends RuntimeException public function __construct( public readonly string $class, public readonly string $property, - public readonly \Throwable $previous, + public readonly ?\Throwable $previous = null, ) { parent::__construct( message: \sprintf(self::MESSAGE, $class, $property),