1
0
mirror of synced 2025-02-02 21:41:45 +03:00

Fix handling entities with post generated IDs as FK

This prevents a throw in UnitOfWork#addToIdentityMap because some fields
are null.
This commit is contained in:
Nicolas FRANÇOIS 2018-01-22 19:10:42 +01:00 committed by Luís Cobucci
parent 23f4f03575
commit 35c3669ebc
No known key found for this signature in database
GPG Key ID: EC61C5F01750ED3C

View File

@ -940,7 +940,11 @@ class UnitOfWork implements PropertyChangedListener
$class->setIdentifierValues($entity, $idValue); $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->entityStates[$oid] = self::STATE_MANAGED;
@ -948,6 +952,20 @@ class UnitOfWork implements PropertyChangedListener
$this->scheduleForInsert($entity); $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: * INTERNAL:
* Computes the changeset of an individual entity, independently of the * Computes the changeset of an individual entity, independently of the
@ -1033,12 +1051,16 @@ class UnitOfWork implements PropertyChangedListener
$persister = $this->getEntityPersister($className); $persister = $this->getEntityPersister($className);
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist); $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
$insertionsForClass = [];
foreach ($this->entityInsertions as $oid => $entity) { foreach ($this->entityInsertions as $oid => $entity) {
if ($this->em->getClassMetadata(get_class($entity))->name !== $className) { if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
continue; continue;
} }
$insertionsForClass[$oid] = $entity;
$persister->addInsert($entity); $persister->addInsert($entity);
unset($this->entityInsertions[$oid]); unset($this->entityInsertions[$oid]);
@ -1067,6 +1089,14 @@ class UnitOfWork implements PropertyChangedListener
$this->addToIdentityMap($entity); $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) { foreach ($entities as $entity) {
@ -1074,6 +1104,30 @@ class UnitOfWork implements PropertyChangedListener
} }
} }
/**
* @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. * Executes all entity updates for entities of the specified type.
* *