Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8238f16

Browse files
committed
[PropertyAccessor] Fix unable to write to singular property using setter while plural adder/remover exist
1 parent 4877d60 commit 8238f16

File tree

3 files changed

+104
-20
lines changed

3 files changed

+104
-20
lines changed

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -707,16 +707,6 @@ private function getWriteAccessInfo($class, $property, $value)
707707
$camelized = $this->camelize($property);
708708
$singulars = (array) Inflector::singularize($camelized);
709709

710-
if (\is_array($value) || $value instanceof \Traversable) {
711-
$methods = $this->findAdderAndRemover($reflClass, $singulars);
712-
713-
if (null !== $methods) {
714-
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
715-
$access[self::ACCESS_ADDER] = $methods[0];
716-
$access[self::ACCESS_REMOVER] = $methods[1];
717-
}
718-
}
719-
720710
if (!isset($access[self::ACCESS_TYPE])) {
721711
$setter = 'set'.$camelized;
722712
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
@@ -738,16 +728,22 @@ private function getWriteAccessInfo($class, $property, $value)
738728
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC;
739729
$access[self::ACCESS_NAME] = $setter;
740730
} elseif (null !== $methods = $this->findAdderAndRemover($reflClass, $singulars)) {
741-
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
742-
$access[self::ACCESS_NAME] = sprintf(
743-
'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
744-
'the new value must be an array or an instance of \Traversable, '.
745-
'"%s" given.',
746-
$property,
747-
$reflClass->name,
748-
implode('()", "', $methods),
749-
\is_object($value) ? \get_class($value) : \gettype($value)
750-
);
731+
if (\is_array($value) || $value instanceof \Traversable) {
732+
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
733+
$access[self::ACCESS_ADDER] = $methods[0];
734+
$access[self::ACCESS_REMOVER] = $methods[1];
735+
} else {
736+
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
737+
$access[self::ACCESS_NAME] = sprintf(
738+
'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
739+
'the new value must be an array or an instance of \Traversable, '.
740+
'"%s" given.',
741+
$property,
742+
$reflClass->name,
743+
implode('()", "', $methods),
744+
\is_object($value) ? \get_class($value) : \gettype($value)
745+
);
746+
}
751747
} else {
752748
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
753749
$access[self::ACCESS_NAME] = sprintf(
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyAccess\Tests\Fixtures;
13+
14+
/**
15+
* Notice we don't have getter/setter for emails
16+
* because we count on adder/remover.
17+
*/
18+
class TestSingularAndPluralProps
19+
{
20+
/** @var string|null */
21+
private $email;
22+
23+
/** @var array */
24+
private $emails = array();
25+
26+
/**
27+
* @return string|null
28+
*/
29+
public function getEmail()
30+
{
31+
return $this->email;
32+
}
33+
34+
/**
35+
* @param string|null $email
36+
*/
37+
public function setEmail($email)
38+
{
39+
$this->email = $email;
40+
}
41+
42+
/**
43+
* @return array
44+
*/
45+
public function getEmails()
46+
{
47+
return $this->emails;
48+
}
49+
50+
/**
51+
* @param string $email
52+
*/
53+
public function addEmail($email)
54+
{
55+
$this->emails[] = $email;
56+
}
57+
58+
/**
59+
* @param string $email
60+
*/
61+
public function removeEmail($email)
62+
{
63+
$this->emails = array_diff($this->emails, array($email));
64+
}
65+
}

src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet;
2323
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassSetValue;
2424
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassTypeErrorInsideCall;
25+
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularAndPluralProps;
2526
use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object;
2627
use Symfony\Component\PropertyAccess\Tests\Fixtures\TypeHinted;
2728

@@ -686,4 +687,26 @@ public function testDoNotDiscardReturnTypeErrorWhenWriterMethodIsMisconfigured()
686687

687688
$this->propertyAccessor->setValue($object, 'name', 'foo');
688689
}
690+
691+
public function testWriteToSingularPropertyWhilePluralOneExists()
692+
{
693+
$object = new TestSingularAndPluralProps();
694+
695+
$this->propertyAccessor->isWritable($object, 'email'); //cache access info
696+
$this->propertyAccessor->setValue($object, 'email', '[email protected]');
697+
698+
self::assertEquals('[email protected]', $object->getEmail());
699+
self::assertEmpty($object->getEmails());
700+
}
701+
702+
public function testWriteToPluralPropertyWhileSingularOneExists()
703+
{
704+
$object = new TestSingularAndPluralProps();
705+
706+
$this->propertyAccessor->isWritable($object, 'emails'); //cache access info
707+
$this->propertyAccessor->setValue($object, 'emails', array('[email protected]'));
708+
709+
self::assertEquals(array('[email protected]'), $object->getEmails());
710+
self::assertNull($object->getEmail());
711+
}
689712
}

0 commit comments

Comments
 (0)