Skip to content

Commit 10c5bc4

Browse files
bendaviesBen Davies
authored andcommitted
[Form] cast IDs to match deprecated behaviour of EntityChoiceList
1 parent 5492b9b commit 10c5bc4

File tree

3 files changed

+194
-1
lines changed

3 files changed

+194
-1
lines changed

Form/ChoiceList/DoctrineChoiceLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public function loadChoicesForValues(array $values, $value = null)
156156
// "INDEX BY" clause to the Doctrine query in the loader,
157157
// but I'm not sure whether that's doable in a generic fashion.
158158
foreach ($unorderedObjects as $object) {
159-
$objectsById[$this->idReader->getIdValue($object)] = $object;
159+
$objectsById[(string) $this->idReader->getIdValue($object)] = $object;
160160
}
161161

162162
foreach ($values as $i => $id) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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\Bridge\Doctrine\Tests\Fixtures;
13+
14+
use Doctrine\ORM\Mapping\Column;
15+
use Doctrine\ORM\Mapping\Entity;
16+
use Doctrine\ORM\Mapping\GeneratedValue;
17+
use Doctrine\ORM\Mapping\Id;
18+
19+
/** @Entity */
20+
class SingleStringCastableIdEntity
21+
{
22+
/**
23+
* @Id
24+
* @Column(type="string")
25+
* @GeneratedValue(strategy="NONE")
26+
*/
27+
protected $id;
28+
29+
/** @Column(type="string", nullable=true) */
30+
public $name;
31+
32+
public function __construct($id, $name)
33+
{
34+
$this->id = new StringCastableObjectIdentity($id);
35+
$this->name = $name;
36+
}
37+
38+
public function __toString()
39+
{
40+
return (string) $this->name;
41+
}
42+
}
43+
44+
class StringCastableObjectIdentity
45+
{
46+
protected $id;
47+
48+
public function __construct($id)
49+
{
50+
$this->id = $id;
51+
}
52+
53+
public function __toString()
54+
{
55+
return (string) $this->id;
56+
}
57+
}

Tests/Form/Type/EntityTypeTest.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity;
2525
use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity;
2626
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
27+
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity;
2728
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity;
2829
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
2930
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
@@ -40,6 +41,7 @@ class EntityTypeTest extends TypeTestCase
4041
const SINGLE_IDENT_NO_TO_STRING_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity';
4142
const SINGLE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity';
4243
const SINGLE_ASSOC_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleAssociationToIntIdEntity';
44+
const SINGLE_STRING_CASTABLE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity';
4345
const COMPOSITE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity';
4446
const COMPOSITE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity';
4547

@@ -67,6 +69,7 @@ protected function setUp()
6769
$this->em->getClassMetadata(self::SINGLE_IDENT_NO_TO_STRING_CLASS),
6870
$this->em->getClassMetadata(self::SINGLE_STRING_IDENT_CLASS),
6971
$this->em->getClassMetadata(self::SINGLE_ASSOC_IDENT_CLASS),
72+
$this->em->getClassMetadata(self::SINGLE_STRING_CASTABLE_IDENT_CLASS),
7073
$this->em->getClassMetadata(self::COMPOSITE_IDENT_CLASS),
7174
$this->em->getClassMetadata(self::COMPOSITE_STRING_IDENT_CLASS),
7275
);
@@ -580,6 +583,139 @@ public function testSubmitMultipleExpandedWithNegativeIntegerId()
580583
$this->assertFalse($field['2']->getData());
581584
}
582585

586+
public function testSubmitSingleNonExpandedStringCastableIdentifier()
587+
{
588+
$entity1 = new SingleStringCastableIdEntity(1, 'Foo');
589+
$entity2 = new SingleStringCastableIdEntity(2, 'Bar');
590+
591+
$this->persist(array($entity1, $entity2));
592+
593+
$field = $this->factory->createNamed('name', 'entity', null, array(
594+
'multiple' => false,
595+
'expanded' => false,
596+
'em' => 'default',
597+
'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
598+
'choice_label' => 'name',
599+
));
600+
601+
$field->submit('2');
602+
603+
$this->assertTrue($field->isSynchronized());
604+
$this->assertSame($entity2, $field->getData());
605+
$this->assertSame('2', $field->getViewData());
606+
}
607+
608+
public function testSubmitSingleStringCastableIdentifierExpanded()
609+
{
610+
$entity1 = new SingleStringCastableIdEntity(1, 'Foo');
611+
$entity2 = new SingleStringCastableIdEntity(2, 'Bar');
612+
613+
$this->persist(array($entity1, $entity2));
614+
615+
$field = $this->factory->createNamed('name', 'entity', null, array(
616+
'multiple' => false,
617+
'expanded' => true,
618+
'em' => 'default',
619+
'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
620+
'choice_label' => 'name',
621+
));
622+
623+
$field->submit('2');
624+
625+
$this->assertTrue($field->isSynchronized());
626+
$this->assertSame($entity2, $field->getData());
627+
$this->assertFalse($field['0']->getData());
628+
$this->assertTrue($field['1']->getData());
629+
$this->assertNull($field['0']->getViewData());
630+
$this->assertSame('2', $field['1']->getViewData());
631+
}
632+
633+
public function testSubmitMultipleNonExpandedStringCastableIdentifierForExistingData()
634+
{
635+
$entity1 = new SingleStringCastableIdEntity(1, 'Foo');
636+
$entity2 = new SingleStringCastableIdEntity(2, 'Bar');
637+
$entity3 = new SingleStringCastableIdEntity(3, 'Baz');
638+
639+
$this->persist(array($entity1, $entity2, $entity3));
640+
641+
$field = $this->factory->createNamed('name', 'entity', null, array(
642+
'multiple' => true,
643+
'expanded' => false,
644+
'em' => 'default',
645+
'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
646+
'choice_label' => 'name',
647+
));
648+
649+
$existing = new ArrayCollection(array(0 => $entity2));
650+
651+
$field->setData($existing);
652+
$field->submit(array('1', '3'));
653+
654+
// entry with index 0 ($entity2) was replaced
655+
$expected = new ArrayCollection(array(0 => $entity1, 1 => $entity3));
656+
657+
$this->assertTrue($field->isSynchronized());
658+
$this->assertEquals($expected, $field->getData());
659+
// same object still, useful if it is a PersistentCollection
660+
$this->assertSame($existing, $field->getData());
661+
$this->assertSame(array('1', '3'), $field->getViewData());
662+
}
663+
664+
public function testSubmitMultipleNonExpandedStringCastableIdentifier()
665+
{
666+
$entity1 = new SingleStringCastableIdEntity(1, 'Foo');
667+
$entity2 = new SingleStringCastableIdEntity(2, 'Bar');
668+
$entity3 = new SingleStringCastableIdEntity(3, 'Baz');
669+
670+
$this->persist(array($entity1, $entity2, $entity3));
671+
672+
$field = $this->factory->createNamed('name', 'entity', null, array(
673+
'multiple' => true,
674+
'expanded' => false,
675+
'em' => 'default',
676+
'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
677+
'choice_label' => 'name',
678+
));
679+
680+
$field->submit(array('1', '3'));
681+
682+
$expected = new ArrayCollection(array($entity1, $entity3));
683+
684+
$this->assertTrue($field->isSynchronized());
685+
$this->assertEquals($expected, $field->getData());
686+
$this->assertSame(array('1', '3'), $field->getViewData());
687+
}
688+
689+
public function testSubmitMultipleStringCastableIdentifierExpanded()
690+
{
691+
$entity1 = new SingleStringCastableIdEntity(1, 'Foo');
692+
$entity2 = new SingleStringCastableIdEntity(2, 'Bar');
693+
$entity3 = new SingleStringCastableIdEntity(3, 'Bar');
694+
695+
$this->persist(array($entity1, $entity2, $entity3));
696+
697+
$field = $this->factory->createNamed('name', 'entity', null, array(
698+
'multiple' => true,
699+
'expanded' => true,
700+
'em' => 'default',
701+
'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
702+
'choice_label' => 'name',
703+
));
704+
705+
$field->submit(array('1', '3'));
706+
707+
$expected = new ArrayCollection(array($entity1, $entity3));
708+
709+
$this->assertTrue($field->isSynchronized());
710+
$this->assertEquals($expected, $field->getData());
711+
$this->assertTrue($field['0']->getData());
712+
$this->assertFalse($field['1']->getData());
713+
$this->assertTrue($field['2']->getData());
714+
$this->assertSame('1', $field['0']->getViewData());
715+
$this->assertNull($field['1']->getViewData());
716+
$this->assertSame('3', $field['2']->getViewData());
717+
}
718+
583719
public function testOverrideChoices()
584720
{
585721
$entity1 = new SingleIntIdEntity(1, 'Foo');

0 commit comments

Comments
 (0)