From 1dcca1a8df40258168e22a58077873a87b3b623a Mon Sep 17 00:00:00 2001 From: Nicolas Macherey Date: Thu, 9 Jul 2015 13:44:18 +0200 Subject: [PATCH] =?UTF-8?q?[PropertyAccess]=C2=A0setValue=20&=20isWritable?= =?UTF-8?q?=20loops=20must=20only=20stops=20on=20reference=20and=20object.?= =?UTF-8?q?=20References=20can=20also=20be=20arrays=20and=20if=20the=20loo?= =?UTF-8?q?p=20stops=20the=20value=20is=20never=20set=20in=20the=20object.?= =?UTF-8?q?=20(Breaks=20since=202.6.5=20commit=20e3e4695)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | This merge request fixes the following cases taht was working with version previous to 2.6.5: A class with a property myArray which can be a multi dimensional array can now be accesed using myArray[foo][bar][baz] Previously only myArray[foo] was working. The break is since commit e3e4695 This commit adds additionnal testing, and is rebased from 2.6 upstream --- .../PropertyAccess/PropertyAccessor.php | 4 +- .../Tests/Fixtures/TestClassIsWritable.php | 27 +++++++++++ .../Tests/Fixtures/TestClassSetValue.php | 32 +++++++++++++ .../Tests/PropertyAccessorTest.php | 45 ++++++++++++++++++- 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassIsWritable.php create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassSetValue.php diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index f13a5c9175..182d9fc024 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -88,7 +88,7 @@ class PropertyAccessor implements PropertyAccessorInterface $this->writeProperty($objectOrArray, $property, $value); } - if ($propertyValues[$i][self::IS_REF]) { + if ($propertyValues[$i][self::IS_REF] && is_object($objectOrArray)) { return; } @@ -149,7 +149,7 @@ class PropertyAccessor implements PropertyAccessorInterface } } - if ($propertyValues[$i][self::IS_REF]) { + if ($propertyValues[$i][self::IS_REF] && is_object($objectOrArray)) { return true; } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassIsWritable.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassIsWritable.php new file mode 100644 index 0000000000..d07c7c0fa8 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassIsWritable.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassIsWritable +{ + protected $value; + + public function getValue() + { + return $this->value; + } + + public function __construct($value) + { + $this->value = $value; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassSetValue.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassSetValue.php new file mode 100644 index 0000000000..638afee6af --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassSetValue.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassSetValue +{ + protected $value; + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } + + public function __construct($value) + { + $this->value = $value; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 9a5324f781..aedca2e822 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -16,6 +16,8 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet; use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassSetValue; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable; class PropertyAccessorTest extends \PHPUnit_Framework_TestCase { @@ -446,4 +448,45 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase $this->propertyAccessor->setValue($obj, 'publicProperty[foo][bar]', 'Updated'); $this->assertSame('Updated', $obj->publicProperty['foo']['bar']); } -} + + public function getReferenceChainObjectsForSetValue() + { + return array( + array(array('a' => array('b' => array('c' => 'old-value'))), '[a][b][c]', 'new-value'), + array(new TestClassSetValue(new TestClassSetValue('old-value')), 'value.value', 'new-value'), + array(new TestClassSetValue(array('a' => array('b' => array('c' => new TestClassSetValue('old-value'))))), 'value[a][b][c].value', 'new-value'), + array(new TestClassSetValue(array('a' => array('b' => 'old-value'))), 'value[a][b]', 'new-value'), + array(new \ArrayIterator(array('a' => array('b' => array('c' => 'old-value')))), '[a][b][c]', 'new-value'), + ); + + } + + /** + * @dataProvider getReferenceChainObjectsForSetValue + */ + public function testSetValueForReferenceChainIssue($object, $path, $value) + { + $this->propertyAccessor->setValue($object, $path, $value); + + $this->assertEquals($value, $this->propertyAccessor->getValue($object, $path)); + } + + public function getReferenceChainObjectsForIsWritable() + { + return array( + array(new TestClassIsWritable(array('a' => array('b' => 'old-value'))), 'value[a][b]', false), + array(new TestClassIsWritable(new \ArrayIterator(array('a' => array('b' => 'old-value')))), 'value[a][b]', true), + array(new TestClassIsWritable(array('a' => array('b' => array('c' => new TestClassSetValue('old-value'))))), 'value[a][b][c].value', true), + ); + + } + + /** + * @dataProvider getReferenceChainObjectsForIsWritable + */ + public function testIsWritableForReferenceChainIssue($object, $path, $value) + { + $this->assertEquals($value, $this->propertyAccessor->isWritable($object, $path)); + } + +} \ No newline at end of file