8000 Merge branch '2.3' into 2.7 · symfony/symfony@e894867 · GitHub
[go: up one dir, main page]

Skip to content

Commit e894867

Browse files
committed
Merge branch '2.3' into 2.7
* 2.3: Implement the support of timezone objects in the stub IntlDateFormatter [DoctrineBridge][Form] Fix EntityChoiceList when indexing by primary foreign key
2 parents b450c84 + d6d93dd commit e894867

9 files changed

+355
-17
lines changed

src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ class EntityChoiceList extends ObjectChoiceList
4545
*/
4646
private $classMetadata;
4747

48+
/**
49+
* Metadata for target class of primary key association.
50+
*
51+
* @var ClassMetadata
52+
*/
53+
private $idClassMetadata;
54+
4855
/**
4956
* Contains the query builder that builds the query for fetching the
5057
* entities.
@@ -112,16 +119,21 @@ public function __construct(ObjectManager $manager, $class, $labelPath = null, E
112119
$this->class = $this->classMetadata->getName();
113120
$this->loaded = is_array($entities) || $entities instanceof \Traversable;
114121
$this->preferredEntities = $preferredEntities;
122+
list(
123+
$this->idAsIndex,
124+
$this->idAsValue,
125+
$this->idField
126+
) = $this->getIdentifierInfoForClass($this->classMetadata);
127+
128+
if (null !== $this->idField && $this->classMetadata->hasAssociation($this->idField)) {
129+
$this->idClassMetadata = $this->em->getClassMetadata(
130+
$this->classMetadata->getAssociationTargetClass($this->idField)
131+
);
115132

116-
$identifier = $this->classMetadata->getIdentifierFieldNames();
117-
118-
if (1 === count($identifier)) {
119-
$this->idField = $identifier[0];
120-
$this->idAsValue = true;
121-
122-
if (in_array($this->classMetadata->getTypeOfField($this->idField), array('integer', 'smallint', 'bigint'))) {
123-
$this->idAsIndex = true;
124-
}
133+
list(
134+
$this->idAsIndex,
135+
$this->idAsValue
136+
) = $this->getIdentifierInfoForClass($this->idClassMetadata);
125137
}
126138

127139
if (!$this->loaded) {
@@ -233,7 +245,7 @@ public function getChoicesForValues(array $values)
233245
// "INDEX BY" clause to the Doctrine query in the loader,
234246
// but I'm not sure whether that's doable in a generic fashion.
235247
foreach ($unorderedEntities as $entity) {
236-
$value = $this->fixValue(current($this->getIdentifierValues($entity)));
248+
$value = $this->fixValue($this->getSingleIdentifierValue($entity));
237249
$entitiesByValue[$value] = $entity;
238250
}
239251

@@ -279,7 +291,7 @@ public function getValuesForChoices(array $entities)
279291
foreach ($entities as $i => $entity) {
280292
if ($entity instanceof $this->class) {
281293
// Make sure to convert to the right format
282-
$values[$i] = $this->fixValue(current($this->getIdentifierValues($entity)));
294+
$values[$i] = $this->fixValue($this->getSingleIdentifierValue($entity));
283295
}
284296
}
285297

@@ -322,7 +334,7 @@ public function getIndicesForChoices(array $entities)
322334
foreach ($entities as $i => $entity) {
323335
if ($entity instanceof $this->class) {
324336
// Make sure to convert to the right format
325-
$indices[$i] = $this->fixIndex(current($this->getIdentifierValues($entity)));
337+
$indices[$i] = $this->fixIndex($this->getSingleIdentifierValue($entity));
326338
}
327339
}
328340

@@ -383,7 +395,7 @@ public function getIndicesForValues(array $values)
383395
protected function createIndex($entity)
384396
{
385397
if ($this->idAsIndex) {
386-
return $this->fixIndex(current($this->getIdentifierValues($entity)));
398+
return $this->fixIndex($this->getSingleIdentifierValue($entity));
387399
}
388400

389401
return parent::createIndex($entity);
@@ -403,7 +415,7 @@ protected function createIndex($entity)
403415
protected function createValue($entity)
404416
{
405417
if ($this->idAsValue) {
406-
return (string) current($this->getIdentifierValues($entity));
418+
return (string) $this->getSingleIdentifierValue($entity);
407419
}
408420

409421
return parent::createValue($entity);
@@ -426,6 +438,36 @@ protected function fixIndex($index)
426438
return $index;
427439
}
428440

441+
/**
442+
* Get identifier information for a class.
443+
*
444+
* @param ClassMetadata $classMetadata The entity metadata
445+
*
446+
* @return array Return an array with idAsIndex, idAsValue and identifier
447+
*/
448+
private function getIdentifierInfoForClass(ClassMetadata $classMetadata)
449+
{
450+
$identifier = null;
451+
$idAsIndex = false;
452+
$idAsValue = false;
453+
454+
$identifiers = $classMetadata->getIdentifierFieldNames();
455+
456+
if (1 === count($identifiers)) {
457+
$identifier = $identifiers[0];
458+
459+
if (!$classMetadata->hasAssociation($identifier)) {
460+
$idAsValue = true;
461+
462+
if (in_array($classMetadata->getTypeOfField($identifier), array('integer', 'smallint', 'bigint'))) {
463+
$idAsIndex = true;
464+
}
465+
}
466+
}
467+
468+
return array($idAsIndex, $idAsValue, $identifier);
469+
}
470+
429471
/**
430472
* Loads the list with entities.
431473
*
@@ -449,6 +491,33 @@ private function load()
449491
$this->loaded = true;
450492
}
451493

494+
/**
495+
* Returns the first (and only) value of the identifier fields of an entity.
496+
*
497+
* Doctrine must know about this entity, that is, the entity must already
498+
* be persisted or added to the identity map before. Otherwise an
499+
* exception is thrown.
500+
*
501+
* @param object $entity The entity for which to get the identifier
502+
*
503+
* @return array The identifier values
504+
*
505+
* @throws RuntimeException If the entity does not exist in Doctrine's identity map
506+
*/
507+
private function getSingleIdentifierValue($entity)
508+
{
509+
$value = current($this->getIdentifierValues($entity));
510+
511+
if ($this->idClassMetadata) {
512+
$class = $this->idClassMetadata->getName();
513+
if ($value instanceof $class) {
514+
$value = current($this->idClassMetadata->getIdentifierValues($value));
515+
}
516+
}
517+
518+
return $value;
519+
}
520+
452521
/**
453522
* Returns the values of the identifier fields of an entity.
454523
*
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Id;
15+
use Doctrine\ORM\Mapping\Column;
16+
use Doctrine\ORM\Mapping\Entity;
17+
use Doctrine\ORM\Mapping\OneToOne;
18+
19+
/** @Entity */
20+
class SingleAssociationToIntIdEntity
21+
{
22+
/** @Id @OneToOne(targetEntity="SingleIntIdNoToStringEntity", cascade={"ALL"}) */
23+
protected $entity;
24+
25+
/** @Column(type="string", nullable=true) */
26+
public $name;
27+
28+
public function __construct(SingleIntIdNoToStringEntity $entity, $name)
29+
{
30+
$this->entity = $entity;
31+
$this->name = $name;
32+
}
33+
34+
public function __toString()
35+
{
36+
return (string) $this->name;
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Form\ChoiceList;
13+
14+
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleAssociationToIntIdEntity;
15+
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity;
16+
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList;
17+
18+
/**
19+
* Test choices generated from an entity with a primary foreign key.
20+
*
21+
* @author Premi Giorgio <giosh94mhz@gmail.com>
22+
* @author Bernhard Schussek <bschussek@gmail.com>
23+
*/
24+
abstract class AbstractEntityChoiceListSingleAssociationToIntIdTest extends AbstractEntityChoiceListTest
25+
{
26+
protected function getEntityClass()
27+
{
28+
return 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleAssociationToIntIdEntity';
29+
}
30+
31+
protected function getClassesMetadata()
32+
{
33+
return array(
34+
$this->em->getClassMetadata($this->getEntityClass()),
35+
$this->em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity'),
36+
);
37+
}
38+
39+
protected function createChoiceList()
40+
{
41+
return new EntityChoiceList($this->em, $this->getEntityClass(), 'name');
42+
}
43+
44+
/**
45+
* @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
46+
*/
47+
protected function createObjects()
48+
{
49+
$innerA = new SingleIntIdNoToStringEntity(-10, 'inner_A');
50+
$innerB = new SingleIntIdNoToStringEntity(10, 'inner_B');
51+
$innerC = new SingleIntIdNoToStringEntity(20, 'inner_C');
52+
$innerD = new SingleIntIdNoToStringEntity(30, 'inner_D');
53+
54+
$this->em->persist($innerA);
55+
$this->em->persist($innerB);
56+
$this->em->persist($innerC);
57+
$this->em->persist($innerD);
58+
59+
return array(
60+
new SingleAssociationToIntIdEntity($innerA, 'A'),
61+
new SingleAssociationToIntIdEntity($innerB, 'B'),
62+
new SingleAssociationToIntIdEntity($innerC, 'C'),
63+
new SingleAssociationToIntIdEntity($innerD, 'D'),
64+
);
65+
}
66+
67+
protected function getChoices()
68+
{
69+
return array('_10' => $this->obj1, 10 => $this->obj2, 20 => $this->obj3, 30 => $this->obj4);
70+
}
71+
72+
protected function getLabels()
73+
{
74+
return array('_10' => 'A', 10 => 'B', 20 => 'C', 30 => 'D');
75+
}
76+
77+
protected function getValues()
78+
{
79+
return array('_10' => '-10', 10 => '10', 20 => '20', 30 => '30');
80+
}
81+
82+
protected function getIndices()
83+
{
84+
return array('_10', 10, 20, 30);
85+
}
86+
}

src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected function setUp()
3939
$this->em = DoctrineTestHelper::createTestEntityManager();
4040

4141
$schemaTool = new SchemaTool($this->em);
42-
$classes = array($this->em->getClassMetadata($this->getEntityClass()));
42+
$classes = $this->getClassesMetadata();
4343

4444
try {
4545
$schemaTool->dropSchema($classes);
@@ -73,6 +73,11 @@ abstract protected function getEntityClass();
7373

7474
abstract protected function createObjects();
7575

76+
protected function getClassesMetadata()
77+
{
78+
return array($this->em->getClassMetadata($this->getEntityClass()));
79+
}
80+
7681
/**
7782
* @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
7883
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Form\ChoiceList;
13+
14+
/**
15+
* @author Premi Giorgio <giosh94mhz@gmail.com>
16+
* @author Bernhard Schussek <bschussek@gmail.com>
17+
*/
18+
class LoadedEntityChoiceListSingleAssociationToIntIdTest extends AbstractEntityChoiceListSingleAssociationToIntIdTest
19+
{
20+
/**
21+
* @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
22+
*/
23+
protected function createChoiceList()
24+
{
25+
$list = parent::createChoiceList();
26+
27+
// load list
28+
$list->getChoices();
29+
30+
return $list;
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Form\ChoiceList;
13+
14+
/**
15+
* @author Premi Giorgio <giosh94mhz@gmail.com>
16+
* @author Bernhard Schussek <bschussek@gmail.com>
17+
*/
18+
class UnloadedEntityChoiceListSingleAssociationToIntIdTest extends AbstractEntityChoiceListSingleAssociationToIntIdTest
19+
{
20+
public function testGetIndicesForValuesIgnoresNonExistingValues()
21+
{
22+
$this->markTestSkipped('Non-existing values are not detected for unloaded choice lists.');
23+
}
24+
25+
/**
26+
* @group legacy
27+
*/
28+
public function testLegacyGetIndicesForValuesIgnoresNonExistingValues()
29+
{
30+
$this->markTestSkipped('Non-existing values are not detected for unloaded choice lists.');
31+
}
32+
}

0 commit comments

Comments
 (0)
0