[PropertyAccess] setValue & isWritable loops must only stops on reference and object. References can also be arrays and if the loop stops the value is never set in the object. (Breaks since 2.6.5 commit e3e4695)
| 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
This commit is contained in:
parent
e6cc4918bf
commit
1dcca1a8df
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user