Skip to content

Commit

Permalink
Merge pull request #6701 from vhenzl/pr/issue-6531-test
Browse files Browse the repository at this point in the history
Add failing tests for #6531 

Fixes #6043
Fixes #6531
Fixes #7002
Fixes #7003
  • Loading branch information
lcobucci committed Feb 19, 2018
2 parents a912fc0 + 35c3669 commit 30a063e
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 1 deletion.
56 changes: 55 additions & 1 deletion lib/Doctrine/ORM/UnitOfWork.php
Expand Up @@ -940,14 +940,32 @@ private function persistNew($class, $entity)
$class->setIdentifierValues($entity, $idValue);
}

$this->entityIdentifiers[$oid] = $idValue;
// Some identifiers may be foreign keys to new entities.
// In this case, we don't have the value yet and should treat it as if we have a post-insert generator
if (! $this->hasMissingIdsWhichAreForeignKeys($class, $idValue)) {
$this->entityIdentifiers[$oid] = $idValue;
}
}

$this->entityStates[$oid] = self::STATE_MANAGED;

$this->scheduleForInsert($entity);
}

/**
* @param mixed[] $idValue
*/
private function hasMissingIdsWhichAreForeignKeys(ClassMetadata $class, array $idValue) : bool
{
foreach ($idValue as $idField => $idFieldValue) {
if ($idFieldValue === null && isset($class->associationMappings[$idField])) {
return true;
}
}

return false;
}

/**
* INTERNAL:
* Computes the changeset of an individual entity, independently of the
Expand Down Expand Up @@ -1033,12 +1051,16 @@ private function executeInserts($class)
$persister = $this->getEntityPersister($className);
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);

$insertionsForClass = [];

foreach ($this->entityInsertions as $oid => $entity) {

if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
continue;
}

$insertionsForClass[$oid] = $entity;

$persister->addInsert($entity);

unset($this->entityInsertions[$oid]);
Expand Down Expand Up @@ -1067,13 +1089,45 @@ private function executeInserts($class)

$this->addToIdentityMap($entity);
}
} else {
foreach ($insertionsForClass as $oid => $entity) {
if (! isset($this->entityIdentifiers[$oid])) {
//entity was not added to identity map because some identifiers are foreign keys to new entities.
//add it now
$this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity);
}
}
}

foreach ($entities as $entity) {
$this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
}
}

/**
* @param object $entity
*/
private function addToEntityIdentifiersAndEntityMap(ClassMetadata $class, string $oid, $entity): void
{
$identifier = [];

foreach ($class->getIdentifierFieldNames() as $idField) {
$value = $class->getFieldValue($entity, $idField);

if (isset($class->associationMappings[$idField])) {
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$value = $this->getSingleIdentifierValue($value);
}

$identifier[$idField] = $this->originalEntityData[$oid][$idField] = $value;
}

$this->entityStates[$oid] = self::STATE_MANAGED;
$this->entityIdentifiers[$oid] = $identifier;

$this->addToIdentityMap($entity);
}

/**
* Executes all entity updates for entities of the specified type.
*
Expand Down
190 changes: 190 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH6531Test.php
@@ -0,0 +1,190 @@
<?php

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Common\Collections\ArrayCollection;

final class GH6531Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp() : void
{
parent::setup();

$this->setUpEntitySchema(
[
GH6531User::class,
GH6531Address::class,
GH6531Article::class,
GH6531ArticleAttribute::class,
GH6531Order::class,
GH6531OrderItem::class,
GH6531Product::class,
]
);
}

/**
* @group 6531
*/
public function testSimpleDerivedIdentity() : void
{
$user = new GH6531User();
$address = new GH6531Address();
$address->user = $user;

$this->_em->persist($user);
$this->_em->persist($address);
$this->_em->flush();

self::assertSame($user, $this->_em->find(GH6531User::class, $user->id));
self::assertSame($address, $this->_em->find(GH6531Address::class, $user));
}

/**
* @group 6531
*/
public function testDynamicAttributes() : void
{
$article = new GH6531Article();
$article->addAttribute('name', 'value');

$this->_em->persist($article);
$this->_em->flush();

self::assertSame(
$article->attributes['name'],
$this->_em->find(GH6531ArticleAttribute::class, ['article' => $article, 'attribute' => 'name'])
);
}

/**
* @group 6531
*/
public function testJoinTableWithMetadata() : void
{
$product = new GH6531Product();
$this->_em->persist($product);
$this->_em->flush();

$order = new GH6531Order();
$order->addItem($product, 2);

$this->_em->persist($order);
$this->_em->flush();

self::assertSame(
$order->items->first(),
$this->_em->find(GH6531OrderItem::class, ['product' => $product, 'order' => $order])
);
}
}

/**
* @Entity
*/
class GH6531User
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}

/**
* @Entity
*/
class GH6531Address
{
/** @Id @OneToOne(targetEntity=GH6531User::class) */
public $user;
}

/**
* @Entity
*/
class GH6531Article
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;

/** @OneToMany(targetEntity=GH6531ArticleAttribute::class, mappedBy="article", cascade={"ALL"}, indexBy="attribute") */
public $attributes;

public function addAttribute(string $name, string $value)
{
$this->attributes[$name] = new GH6531ArticleAttribute($name, $value, $this);
}
}

/**
* @Entity
*/
class GH6531ArticleAttribute
{
/** @Id @ManyToOne(targetEntity=GH6531Article::class, inversedBy="attributes") */
public $article;

/** @Id @Column(type="string") */
public $attribute;

/** @Column(type="string") */
public $value;

public function __construct(string $name, string $value, GH6531Article $article)
{
$this->attribute = $name;
$this->value = $value;
$this->article = $article;
}
}

/**
* @Entity
*/
class GH6531Order
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;

/** @OneToMany(targetEntity=GH6531OrderItem::class, mappedBy="order", cascade={"ALL"}) */
public $items;

public function __construct()
{
$this->items = new ArrayCollection();
}

public function addItem(GH6531Product $product, int $amount) : void
{
$this->items->add(new GH6531OrderItem($this, $product, $amount));
}
}

/**
* @Entity
*/
class GH6531Product
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}

/**
* @Entity
*/
class GH6531OrderItem
{
/** @Id @ManyToOne(targetEntity=GH6531Order::class) */
public $order;

/** @Id @ManyToOne(targetEntity=GH6531Product::class) */
public $product;

/** @Column(type="integer") */
public $amount = 1;

public function __construct(GH6531Order $order, GH6531Product $product, int $amount = 1)
{
$this->order = $order;
$this->product = $product;
$this->amount = $amount;
}
}

0 comments on commit 30a063e

Please sign in to comment.