From 54bbade3e6efc9fbabb09b493316f9f50130bdd9 Mon Sep 17 00:00:00 2001 From: Ben Davies Date: Mon, 14 Dec 2015 15:27:04 +0000 Subject: [PATCH] [Form] cast IDs to match deprecated behaviour of EntityChoiceList --- .../Form/ChoiceList/DoctrineChoiceLoader.php | 2 +- .../Fixtures/SingleStringCastableIdEntity.php | 57 ++++++++ .../Tests/Form/Type/EntityTypeTest.php | 136 ++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 2335af7131..1a09609b28 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -156,7 +156,7 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface // "INDEX BY" clause to the Doctrine query in the loader, // but I'm not sure whether that's doable in a generic fashion. foreach ($unorderedObjects as $object) { - $objectsById[$this->idReader->getIdValue($object)] = $object; + $objectsById[(string) $this->idReader->getIdValue($object)] = $object; } foreach ($values as $i => $id) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php new file mode 100644 index 0000000000..e457f69dd0 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\GeneratedValue; +use Doctrine\ORM\Mapping\Id; + +/** @Entity */ +class SingleStringCastableIdEntity +{ + /** + * @Id + * @Column(type="string") + * @GeneratedValue(strategy="NONE") + */ + protected $id; + + /** @Column(type="string", nullable=true) */ + public $name; + + public function __construct($id, $name) + { + $this->id = new StringCastableObjectIdentity($id); + $this->name = $name; + } + + public function __toString() + { + return (string) $this->name; + } +} + +class StringCastableObjectIdentity +{ + protected $id; + + public function __construct($id) + { + $this->id = $id; + } + + public function __toString() + { + return (string) $this->id; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 78f10848bc..ce37d261c0 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -24,6 +24,7 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; @@ -40,6 +41,7 @@ class EntityTypeTest extends TypeTestCase const SINGLE_IDENT_NO_TO_STRING_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity'; const SINGLE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity'; const SINGLE_ASSOC_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleAssociationToIntIdEntity'; + const SINGLE_STRING_CASTABLE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity'; const COMPOSITE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'; const COMPOSITE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity'; @@ -67,6 +69,7 @@ class EntityTypeTest extends TypeTestCase $this->em->getClassMetadata(self::SINGLE_IDENT_NO_TO_STRING_CLASS), $this->em->getClassMetadata(self::SINGLE_STRING_IDENT_CLASS), $this->em->getClassMetadata(self::SINGLE_ASSOC_IDENT_CLASS), + $this->em->getClassMetadata(self::SINGLE_STRING_CASTABLE_IDENT_CLASS), $this->em->getClassMetadata(self::COMPOSITE_IDENT_CLASS), $this->em->getClassMetadata(self::COMPOSITE_STRING_IDENT_CLASS), ); @@ -580,6 +583,139 @@ class EntityTypeTest extends TypeTestCase $this->assertFalse($field['2']->getData()); } + public function testSubmitSingleNonExpandedStringCastableIdentifier() + { + $entity1 = new SingleStringCastableIdEntity(1, 'Foo'); + $entity2 = new SingleStringCastableIdEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = $this->factory->createNamed('name', 'entity', null, array( + 'multiple' => false, + 'expanded' => false, + 'em' => 'default', + 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS, + 'choice_label' => 'name', + )); + + $field->submit('2'); + + $this->assertTrue($field->isSynchronized()); + $this->assertSame($entity2, $field->getData()); + $this->assertSame('2', $field->getViewData()); + } + + public function testSubmitSingleStringCastableIdentifierExpanded() + { + $entity1 = new SingleStringCastableIdEntity(1, 'Foo'); + $entity2 = new SingleStringCastableIdEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = $this->factory->createNamed('name', 'entity', null, array( + 'multiple' => false, + 'expanded' => true, + 'em' => 'default', + 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS, + 'choice_label' => 'name', + )); + + $field->submit('2'); + + $this->assertTrue($field->isSynchronized()); + $this->assertSame($entity2, $field->getData()); + $this->assertFalse($field['0']->getData()); + $this->assertTrue($field['1']->getData()); + $this->assertNull($field['0']->getViewData()); + $this->assertSame('2', $field['1']->getViewData()); + } + + public function testSubmitMultipleNonExpandedStringCastableIdentifierForExistingData() + { + $entity1 = new SingleStringCastableIdEntity(1, 'Foo'); + $entity2 = new SingleStringCastableIdEntity(2, 'Bar'); + $entity3 = new SingleStringCastableIdEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = $this->factory->createNamed('name', 'entity', null, array( + 'multiple' => true, + 'expanded' => false, + 'em' => 'default', + 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS, + 'choice_label' => 'name', + )); + + $existing = new ArrayCollection(array(0 => $entity2)); + + $field->setData($existing); + $field->submit(array('1', '3')); + + // entry with index 0 ($entity2) was replaced + $expected = new ArrayCollection(array(0 => $entity1, 1 => $entity3)); + + $this->assertTrue($field->isSynchronized()); + $this->assertEquals($expected, $field->getData()); + // same object still, useful if it is a PersistentCollection + $this->assertSame($existing, $field->getData()); + $this->assertSame(array('1', '3'), $field->getViewData()); + } + + public function testSubmitMultipleNonExpandedStringCastableIdentifier() + { + $entity1 = new SingleStringCastableIdEntity(1, 'Foo'); + $entity2 = new SingleStringCastableIdEntity(2, 'Bar'); + $entity3 = new SingleStringCastableIdEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = $this->factory->createNamed('name', 'entity', null, array( + 'multiple' => true, + 'expanded' => false, + 'em' => 'default', + 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS, + 'choice_label' => 'name', + )); + + $field->submit(array('1', '3')); + + $expected = new ArrayCollection(array($entity1, $entity3)); + + $this->assertTrue($field->isSynchronized()); + $this->assertEquals($expected, $field->getData()); + $this->assertSame(array('1', '3'), $field->getViewData()); + } + + public function testSubmitMultipleStringCastableIdentifierExpanded() + { + $entity1 = new SingleStringCastableIdEntity(1, 'Foo'); + $entity2 = new SingleStringCastableIdEntity(2, 'Bar'); + $entity3 = new SingleStringCastableIdEntity(3, 'Bar'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = $this->factory->createNamed('name', 'entity', null, array( + 'multiple' => true, + 'expanded' => true, + 'em' => 'default', + 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS, + 'choice_label' => 'name', + )); + + $field->submit(array('1', '3')); + + $expected = new ArrayCollection(array($entity1, $entity3)); + + $this->assertTrue($field->isSynchronized()); + $this->assertEquals($expected, $field->getData()); + $this->assertTrue($field['0']->getData()); + $this->assertFalse($field['1']->getData()); + $this->assertTrue($field['2']->getData()); + $this->assertSame('1', $field['0']->getViewData()); + $this->assertNull($field['1']->getViewData()); + $this->assertSame('3', $field['2']->getViewData()); + } + public function testOverrideChoices() { $entity1 = new SingleIntIdEntity(1, 'Foo');