diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 981823fd07f10..79aded380fe3c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -30,6 +30,7 @@ CHANGELOG * Added support for boolean container parameters within routes. * Added the `messenger:setup-transports` command to setup messenger transports * Added a `InMemoryTransport` to Messenger. Use it with a DSN starting with `in-memory://`. + * Added `framework.property_access.throw_exception_on_invalid_property_path` config option. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 076a70c818768..698ef88e021f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -903,6 +903,7 @@ private function addPropertyAccessSection(ArrayNodeDefinition $rootNode) ->children() ->booleanNode('magic_call')->defaultFalse()->end() ->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end() + ->booleanNode('throw_exception_on_invalid_property_path')->defaultTrue()->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 5ef5ed7b5d269..afca88af956d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1361,6 +1361,7 @@ private function registerPropertyAccessConfiguration(array $config, ContainerBui ->getDefinition('property_accessor') ->replaceArgument(0, $config['magic_call']) ->replaceArgument(1, $config['throw_exception_on_invalid_index']) + ->replaceArgument(3, $config['throw_exception_on_invalid_property_path']) ; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml index 4fb4f2ff98abc..424f9f682d796 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml @@ -11,6 +11,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 38e60f6516846..5a807403a01ad 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -233,6 +233,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index aa0a2fc921853..a9d7d0a63bf6c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -249,6 +249,7 @@ protected static function getBundleDefaultConfig() 'property_access' => [ 'magic_call' => false, 'throw_exception_on_invalid_index' => false, + 'throw_exception_on_invalid_property_path' => true, ], 'property_info' => [ 'enabled' => !class_exists(FullStack::class), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php index b5b060c1baa43..8f431f8735d89 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php @@ -4,5 +4,6 @@ 'property_access' => [ 'magic_call' => true, 'throw_exception_on_invalid_index' => true, + 'throw_exception_on_invalid_property_path' => false, ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml index 95ddef8288e38..07e33ae3e8d96 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml @@ -7,6 +7,6 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml index b5fd2718ab112..ea527c9821116 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml @@ -2,3 +2,4 @@ framework: property_access: magic_call: true throw_exception_on_invalid_index: true + throw_exception_on_invalid_property_path: false diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index acc7fbad156e7..1b8a785a303db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -80,6 +80,7 @@ public function testPropertyAccessWithDefaultValue() $def = $container->getDefinition('property_accessor'); $this->assertFalse($def->getArgument(0)); $this->assertFalse($def->getArgument(1)); + $this->assertTrue($def->getArgument(3)); } public function testPropertyAccessWithOverriddenValues() @@ -88,6 +89,7 @@ public function testPropertyAccessWithOverriddenValues() $def = $container->getDefinition('property_accessor'); $this->assertTrue($def->getArgument(0)); $this->assertTrue($def->getArgument(1)); + $this->assertFalse($def->getArgument(3)); } public function testPropertyAccessCache() diff --git a/src/Symfony/Component/PropertyAccess/CHANGELOG.md b/src/Symfony/Component/PropertyAccess/CHANGELOG.md index 970f3545b5702..0a012bb47620d 100644 --- a/src/Symfony/Component/PropertyAccess/CHANGELOG.md +++ b/src/Symfony/Component/PropertyAccess/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +4.3.0 +----- + +* added a `$throwExceptionOnInvalidPropertyPath` argument to the PropertyAccessor constructor. +* added `enableExceptionOnInvalidPropertyPath()`, `disableExceptionOnInvalidPropertyPath()` and + `isExceptionOnInvalidPropertyPath()` methods to `PropertyAccessorBuilder` + 4.0.0 ----- diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index db9c6b84652ea..891cc5e75ea46 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -56,6 +56,7 @@ class PropertyAccessor implements PropertyAccessorInterface */ private $magicCall; private $ignoreInvalidIndices; + private $ignoreInvalidProperty; /** * @var CacheItemPoolInterface @@ -70,11 +71,12 @@ class PropertyAccessor implements PropertyAccessorInterface * Should not be used by application code. Use * {@link PropertyAccess::createPropertyAccessor()} instead. */ - public function __construct(bool $magicCall = false, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null) + public function __construct(bool $magicCall = false, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null, bool $throwExceptionOnInvalidPropertyPath = true) { $this->magicCall = $magicCall; $this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex; $this->cacheItemPool = $cacheItemPool instanceof NullAdapter ? null : $cacheItemPool; // Replace the NullAdapter by the null value + $this->ignoreInvalidProperty = !$throwExceptionOnInvalidPropertyPath; } /** @@ -87,7 +89,7 @@ public function getValue($objectOrArray, $propertyPath) ]; if (\is_object($objectOrArray) && false === strpbrk((string) $propertyPath, '.[')) { - return $this->readProperty($zval, $propertyPath)[self::VALUE]; + return $this->readProperty($zval, $propertyPath, $this->ignoreInvalidProperty)[self::VALUE]; } $propertyPath = $this->getPropertyPath($propertyPath); @@ -313,7 +315,7 @@ private function readPropertiesUntil($zval, PropertyPathInterface $propertyPath, $zval = $this->readIndex($zval, $property); } else { - $zval = $this->readProperty($zval, $property); + $zval = $this->readProperty($zval, $property, $this->ignoreInvalidProperty); } // the final value of the path must not be validated @@ -372,14 +374,15 @@ private function readIndex($zval, $index) /** * Reads the a property from an object. * - * @param array $zval The array containing the object to read from - * @param string $property The property to read + * @param array $zval The array containing the object to read from + * @param string $property The property to read + * @param bool $ignoreInvalidProperty Whether to ignore invalid property or throw an exception * * @return array The array containing the value of the property * - * @throws NoSuchPropertyException if the property does not exist or is not public + * @throws NoSuchPropertyException If $ignoreInvalidProperty is false and the property does not exist or is not public */ - private function readProperty($zval, $property) + private function readProperty($zval, $property, bool $ignoreInvalidProperty = false) { if (!\is_object($zval[self::VALUE])) { throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you intended to write the property path as "[%1$s]" instead.', $property)); @@ -411,7 +414,7 @@ private function readProperty($zval, $property) } elseif (self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]) { // we call the getter and hope the __call do the job $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}(); - } else { + } elseif (!$ignoreInvalidProperty) { throw new NoSuchPropertyException($access[self::ACCESS_NAME]); } diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php index 1db6a1dba23ed..a300bdc6f5c36 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php @@ -22,6 +22,7 @@ class PropertyAccessorBuilder { private $magicCall = false; private $throwExceptionOnInvalidIndex = false; + private $throwExceptionOnInvalidPropertyPath = true; /** * @var CacheItemPoolInterface|null @@ -97,6 +98,43 @@ public function isExceptionOnInvalidIndexEnabled() return $this->throwExceptionOnInvalidIndex; } + /** + * Enables exceptions when reading a non-existing property. + * + * This has no influence on writing non-existing indices with PropertyAccessorInterface::setValue() + * which are always created on-the-fly. + * + * @return $this + */ + public function enableExceptionOnInvalidPropertyPath() + { + $this->throwExceptionOnInvalidPropertyPath = true; + + return $this; + } + + /** + * Disables exceptions when reading a non-existing index. + * + * Instead, null is returned when calling PropertyAccessorInterface::getValue() on a non-existing index. + * + * @return $this + */ + public function disableExceptionOnInvalidPropertyPath() + { + $this->throwExceptionOnInvalidPropertyPath = false; + + return $this; + } + + /** + * @return bool whether an exception is thrown or null is returned when reading a non-existing property + */ + public function isExceptionOnInvalidPropertyPath() + { + return $this->throwExceptionOnInvalidPropertyPath; + } + /** * Sets a cache system. * @@ -128,6 +166,6 @@ public function getCacheItemPool() */ public function getPropertyAccessor() { - return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool); + return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool, $this->throwExceptionOnInvalidPropertyPath); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 2a7dd8a83192b..d0cbccf1ec63c 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; @@ -100,6 +101,16 @@ public function testGetValueThrowsExceptionIfPropertyNotFound($objectOrArray, $p $this->propertyAccessor->getValue($objectOrArray, $path); } + /** + * @dataProvider getPathsWithMissingProperty + */ + public function testGetValueReturnsNullIfPropertyNotFoundAndExceptionIsDisabled($objectOrArray, $path) + { + $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()->disableExceptionOnInvalidPropertyPath()->getPropertyAccessor(); + + $this->assertNull($this->propertyAccessor->getValue($objectOrArray, $path), $path); + } + /** * @dataProvider getPathsWithMissingIndex */ @@ -618,6 +629,25 @@ public function testAnonymousClassRead() $this->assertEquals($value, $propertyAccessor->getValue($obj, 'foo')); } + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testAnonymousClassReadThrowExceptionOnInvalidPropertyPath() + { + $obj = $this->generateAnonymousClass('bar'); + + $this->propertyAccessor->getValue($obj, 'invalid_property'); + } + + public function testAnonymousClassReadReturnsNullOnInvalidPropertyWithDisabledException() + { + $obj = $this->generateAnonymousClass('bar'); + + $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()->disableExceptionOnInvalidPropertyPath()->getPropertyAccessor(); + + $this->assertNull($this->propertyAccessor->getValue($obj, 'invalid_property')); + } + public function testAnonymousClassWrite() { $value = 'bar'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy