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

Skip to content

Commit 91acb40

Browse files
authored
Merge pull request #7054 from cb8/foreign-id
Fix ID generation of foreign keys Ports #6701 using v3.0 structure.
2 parents 3e1d124 + 5fde371 commit 91acb40

4 files changed

Lines changed: 255 additions & 24 deletions

File tree

lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@
1313
use Doctrine\ORM\Events;
1414
use Doctrine\ORM\ORMException;
1515
use Doctrine\ORM\Sequencing;
16+
use Doctrine\ORM\Sequencing\Planning\AssociationValueGeneratorExecutor;
1617
use Doctrine\ORM\Sequencing\Planning\ColumnValueGeneratorExecutor;
1718
use Doctrine\ORM\Sequencing\Planning\CompositeValueGenerationPlan;
1819
use Doctrine\ORM\Sequencing\Planning\NoopValueGenerationPlan;
1920
use Doctrine\ORM\Sequencing\Planning\SingleValueGenerationPlan;
21+
use Doctrine\ORM\Sequencing\Planning\ValueGenerationExecutor;
2022
use ReflectionException;
2123
use function array_map;
2224
use function class_exists;
2325
use function count;
2426
use function end;
2527
use function explode;
2628
use function is_subclass_of;
27-
use function reset;
2829
use function sprintf;
2930
use function strpos;
3031
use function strtolower;
@@ -524,41 +525,56 @@ private function getTargetPlatform() : Platforms\AbstractPlatform
524525

525526
private function buildValueGenerationPlan(ClassMetadata $class) : void
526527
{
527-
/** @var LocalColumnMetadata[] $generatedProperties */
528-
$generatedProperties = [];
528+
$executors = $this->buildValueGenerationExecutorList($class);
529529

530-
foreach ($class->getDeclaredPropertiesIterator() as $property) {
531-
if (! ($property instanceof LocalColumnMetadata && $property->hasValueGenerator())) {
532-
continue;
533-
}
534-
535-
$generatedProperties[] = $property;
536-
}
537-
538-
switch (count($generatedProperties)) {
530+
switch (count($executors)) {
539531
case 0:
540532
$class->setValueGenerationPlan(new NoopValueGenerationPlan());
541533
break;
542534

543535
case 1:
544-
$property = reset($generatedProperties);
545-
$executor = new ColumnValueGeneratorExecutor($property, $this->createPropertyValueGenerator($class, $property));
546-
547-
$class->setValueGenerationPlan(new SingleValueGenerationPlan($class, $executor));
536+
$class->setValueGenerationPlan(new SingleValueGenerationPlan($class, $executors[0]));
548537
break;
549538

550539
default:
551-
$executors = [];
552-
553-
foreach ($generatedProperties as $property) {
554-
$executors[] = new ColumnValueGeneratorExecutor($property, $this->createPropertyValueGenerator($class, $property));
555-
}
556-
557540
$class->setValueGenerationPlan(new CompositeValueGenerationPlan($class, $executors));
558541
break;
559542
}
560543
}
561544

545+
/**
546+
* @return ValueGenerationExecutor[]
547+
*/
548+
private function buildValueGenerationExecutorList(ClassMetadata $class) : array
549+
{
550+
$executors = [];
551+
552+
foreach ($class->getDeclaredPropertiesIterator() as $property) {
553+
$executor = $this->buildValueGenerationExecutorForProperty($class, $property);
554+
555+
if ($executor instanceof ValueGenerationExecutor) {
556+
$executors[] = $executor;
557+
}
558+
}
559+
560+
return $executors;
561+
}
562+
563+
private function buildValueGenerationExecutorForProperty(
564+
ClassMetadata $class,
565+
Property $property
566+
) : ?ValueGenerationExecutor {
567+
if ($property instanceof LocalColumnMetadata && $property->hasValueGenerator()) {
568+
return new ColumnValueGeneratorExecutor($property, $this->createPropertyValueGenerator($class, $property));
569+
}
570+
571+
if ($property instanceof ToOneAssociationMetadata && $property->isPrimaryKey()) {
572+
return new AssociationValueGeneratorExecutor();
573+
}
574+
575+
return null;
576+
}
577+
562578
private function createPropertyValueGenerator(
563579
ClassMetadata $class,
564580
LocalColumnMetadata $property
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\ORM\Sequencing\Planning;
6+
7+
use Doctrine\ORM\EntityManagerInterface;
8+
9+
final class AssociationValueGeneratorExecutor implements ValueGenerationExecutor
10+
{
11+
/**
12+
* {@inheritdoc}
13+
*/
14+
public function execute(EntityManagerInterface $entityManager, object $entity) : array
15+
{
16+
// value set by inverse side
17+
return [];
18+
}
19+
20+
public function isDeferred() : bool
21+
{
22+
return true;
23+
}
24+
}

lib/Doctrine/ORM/UnitOfWork.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,9 @@ private function executeInserts(ClassMetadata $class) : void
962962
if ($generationPlan->containsDeferred()) {
963963
// Entity has post-insert IDs
964964
$oid = spl_object_id($entity);
965-
$id = $this->em->getIdentifierFlattener()->flattenIdentifier($class, $persister->getIdentifier($entity));
965+
$id = $persister->getIdentifier($entity);
966966

967-
$this->entityIdentifiers[$oid] = $id;
967+
$this->entityIdentifiers[$oid] = $this->em->getIdentifierFlattener()->flattenIdentifier($class, $id);
968968
$this->entityStates[$oid] = self::STATE_MANAGED;
969969
$this->originalEntityData[$oid] = $id + $this->originalEntityData[$oid];
970970

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<?php
2+
3+
namespace Doctrine\Tests\ORM\Functional\Ticket;
4+
5+
use Doctrine\ORM\Annotation as ORM;
6+
use Doctrine\Common\Collections\ArrayCollection;
7+
8+
final class GH6531Test extends \Doctrine\Tests\OrmFunctionalTestCase
9+
{
10+
protected function setUp() : void
11+
{
12+
parent::setup();
13+
14+
$this->setUpEntitySchema(
15+
[
16+
GH6531User::class,
17+
GH6531Address::class,
18+
GH6531Article::class,
19+
GH6531ArticleAttribute::class,
20+
GH6531Order::class,
21+
GH6531OrderItem::class,
22+
GH6531Product::class,
23+
]
24+
);
25+
}
26+
27+
/**
28+
* @group 6531
29+
*/
30+
public function testSimpleDerivedIdentity() : void
31+
{
32+
$user = new GH6531User();
33+
$address = new GH6531Address();
34+
$address->user = $user;
35+
36+
$this->em->persist($user);
37+
$this->em->persist($address);
38+
$this->em->flush();
39+
40+
self::assertSame($user, $this->em->find(GH6531User::class, $user->id));
41+
self::assertSame($address, $this->em->find(GH6531Address::class, $user));
42+
}
43+
44+
/**
45+
* @group 6531
46+
*/
47+
public function testDynamicAttributes() : void
48+
{
49+
$article = new GH6531Article();
50+
$article->addAttribute('name', 'value');
51+
52+
$this->em->persist($article);
53+
$this->em->flush();
54+
55+
self::assertSame(
56+
$article->attributes['name'],
57+
$this->em->find(GH6531ArticleAttribute::class, ['article' => $article, 'attribute' => 'name'])
58+
);
59+
}
60+
61+
/**
62+
* @group 6531
63+
*/
64+
public function testJoinTableWithMetadata() : void
65+
{
66+
$product = new GH6531Product();
67+
$this->em->persist($product);
68+
$this->em->flush();
69+
70+
$order = new GH6531Order();
71+
$order->addItem($product, 2);
72+
73+
$this->em->persist($order);
74+
$this->em->flush();
75+
76+
self::assertSame(
77+
$order->items->first(),
78+
$this->em->find(GH6531OrderItem::class, ['product' => $product, 'order' => $order])
79+
);
80+
}
81+
}
82+
83+
/**
84+
* @ORM\Entity
85+
*/
86+
class GH6531User
87+
{
88+
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
89+
public $id;
90+
}
91+
92+
/**
93+
* @ORM\Entity
94+
*/
95+
class GH6531Address
96+
{
97+
/** @ORM\Id @ORM\OneToOne(targetEntity=GH6531User::class) */
98+
public $user;
99+
}
100+
101+
/**
102+
* @ORM\Entity
103+
*/
104+
class GH6531Article
105+
{
106+
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
107+
public $id;
108+
109+
/** @ORM\OneToMany(targetEntity=GH6531ArticleAttribute::class, mappedBy="article", cascade={"ALL"}, indexBy="attribute") */
110+
public $attributes;
111+
112+
public function addAttribute(string $name, string $value)
113+
{
114+
$this->attributes[$name] = new GH6531ArticleAttribute($name, $value, $this);
115+
}
116+
}
117+
118+
/**
119+
* @ORM\Entity
120+
*/
121+
class GH6531ArticleAttribute
122+
{
123+
/** @ORM\Id @ORM\ManyToOne(targetEntity=GH6531Article::class, inversedBy="attributes") */
124+
public $article;
125+
126+
/** @ORM\Id @ORM\Column(type="string") */
127+
public $attribute;
128+
129+
/** @ORM\Column(type="string") */
130+
public $value;
131+
132+
public function __construct(string $name, string $value, GH6531Article $article)
133+
{
134+
$this->attribute = $name;
135+
$this->value = $value;
136+
$this->article = $article;
137+
}
138+
}
139+
140+
/**
141+
* @ORM\Entity
142+
*/
143+
class GH6531Order
144+
{
145+
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
146+
public $id;
147+
148+
/** @ORM\OneToMany(targetEntity=GH6531OrderItem::class, mappedBy="order", cascade={"ALL"}) */
149+
public $items;
150+
151+
public function __construct()
152+
{
153+
$this->items = new ArrayCollection();
154+
}
155+
156+
public function addItem(GH6531Product $product, int $amount) : void
157+
{
158+
$this->items->add(new GH6531OrderItem($this, $product, $amount));
159+
}
160+
}
161+
162+
/**
163+
* @ORM\Entity
164+
*/
165+
class GH6531Product
166+
{
167+
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
168+
public $id;
169+
}
170+
171+
/**
172+
* @ORM\Entity
173+
*/
174+
class GH6531OrderItem
175+
{
176+
/** @ORM\Id @ORM\ManyToOne(targetEntity=GH6531Order::class) */
177+
public $order;
178+
179+
/** @ORM\Id @ORM\ManyToOne(targetEntity=GH6531Product::class) */
180+
public $product;
181+
182+
/** @ORM\Column(type="integer") */
183+
public $amount = 1;
184+
185+
public function __construct(GH6531Order $order, GH6531Product $product, int $amount = 1)
186+
{
187+
$this->order = $order;
188+
$this->product = $product;
189+
$this->amount = $amount;
190+
}
191+
}

0 commit comments

Comments
 (0)