[2.0] Fixed issue with self-referential one-to-many associations not being persisted correctly when IDENTITY key generation was used. Included now passing OneToManySelfReferentialTest.
This commit is contained in:
parent
4e70e5d80a
commit
f064de2af1
10 changed files with 128 additions and 84 deletions
|
@ -187,8 +187,8 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
|||
$this->_prepareData($entity, $updateData);
|
||||
|
||||
$id = array_combine(
|
||||
$this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
|
||||
$this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
|
||||
);
|
||||
|
||||
foreach ($updateData as $tableName => $data) {
|
||||
|
@ -205,15 +205,15 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
|||
public function delete($entity)
|
||||
{
|
||||
$id = array_combine(
|
||||
$this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
|
||||
$this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
|
||||
);
|
||||
|
||||
// If the database platform supports FKs, just
|
||||
// delete the row from the root table. Cascades do the rest.
|
||||
if ($this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->_conn->delete($this->_em->getClassMetadata($this->_class->rootEntityName)
|
||||
->primaryTable['name'], $id);
|
||||
->primaryTable['name'], $id);
|
||||
} else {
|
||||
// Delete the parent tables, starting from this class' table up to the root table
|
||||
$this->_conn->delete($this->_class->primaryTable['name'], $id);
|
||||
|
|
|
@ -179,16 +179,18 @@ class StandardEntityPersister
|
|||
{
|
||||
$updateData = array();
|
||||
$this->_prepareData($entity, $updateData);
|
||||
$id = array_combine($this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity));
|
||||
$id = array_combine(
|
||||
$this->_class->getIdentifierFieldNames(),
|
||||
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
|
||||
);
|
||||
$tableName = $this->_class->primaryTable['name'];
|
||||
|
||||
|
||||
if ($this->_evm->hasListeners(Events::preUpdate)) {
|
||||
$this->_preUpdate($entity);
|
||||
}
|
||||
|
||||
|
||||
$this->_conn->update($tableName, $updateData[$tableName], $id);
|
||||
|
||||
|
||||
if ($this->_evm->hasListeners(Events::postUpdate)) {
|
||||
$this->_postUpdate($entity);
|
||||
}
|
||||
|
@ -239,9 +241,10 @@ class StandardEntityPersister
|
|||
}
|
||||
|
||||
/**
|
||||
* Prepares the data changeset of an entity for database insertion.
|
||||
* The array that is passed as the second parameter is filled with
|
||||
* <columnName> => <value> pairs, grouped by table name, during this preparation.
|
||||
* Prepares the data changeset of an entity for database insertion (INSERT/UPDATE).
|
||||
*
|
||||
* During this preparation the array that is passed as the second parameter is filled with
|
||||
* <columnName> => <value> pairs, grouped by table name.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
|
@ -256,7 +259,7 @@ class StandardEntityPersister
|
|||
*
|
||||
* @param object $entity
|
||||
* @param array $result The reference to the data array.
|
||||
* @param boolean $isInsert
|
||||
* @param boolean $isInsert Whether the preparation is for an INSERT (or UPDATE, if FALSE).
|
||||
*/
|
||||
protected function _prepareData($entity, array &$result, $isInsert = false)
|
||||
{
|
||||
|
@ -276,37 +279,43 @@ class StandardEntityPersister
|
|||
continue;
|
||||
}
|
||||
|
||||
// Special case: One-one self-referencing of the same class.
|
||||
if ($newVal !== null && $assocMapping->sourceEntityName == $assocMapping->targetEntityName) {
|
||||
// Special case: One-one self-referencing of the same class with IDENTITY type key generation.
|
||||
if ($this->_class->isIdGeneratorIdentity() && $newVal !== null &&
|
||||
$assocMapping->sourceEntityName == $assocMapping->targetEntityName) {
|
||||
$oid = spl_object_hash($newVal);
|
||||
$isScheduledForInsert = $uow->isRegisteredNew($newVal);
|
||||
if (isset($this->_queuedInserts[$oid]) || $isScheduledForInsert) {
|
||||
// The associated entity $newVal is not yet persisted, so we must
|
||||
// set $newVal = null, in order to insert a null value and update later.
|
||||
// set $newVal = null, in order to insert a null value and schedule an
|
||||
// extra update on the UnitOfWork.
|
||||
$uow->scheduleExtraUpdate($entity, array(
|
||||
$field => array(null, $newVal)
|
||||
));
|
||||
$newVal = null;
|
||||
} else if ($isInsert && ! $isScheduledForInsert && $uow->getEntityState($newVal) == UnitOfWork::STATE_MANAGED) {
|
||||
// $newVal is already fully persisted
|
||||
// Clear changeset of $newVal, so that only the identifier is updated.
|
||||
// Not sure this is really rock-solid here but it seems to work.
|
||||
$uow->clearEntityChangeSet($oid);
|
||||
$uow->propertyChanged($newVal, $field, $entity, $entity);
|
||||
// $newVal is already fully persisted.
|
||||
// Schedule an extra update for it, so that the foreign key(s) are properly set.
|
||||
$uow->scheduleExtraUpdate($newVal, array(
|
||||
$field => array(null, $entity)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
||||
if ($newVal === null) {
|
||||
$result[$this->getOwningTable($field)][$sourceColumn] = null;
|
||||
} else {
|
||||
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
||||
$result[$this->getOwningTable($field)][$sourceColumn] =
|
||||
$otherClass->reflFields[$otherClass->fieldNames[$targetColumn]]->getValue($newVal);
|
||||
$otherClass->reflFields[$otherClass->fieldNames[$targetColumn]]
|
||||
->getValue($newVal);
|
||||
}
|
||||
}
|
||||
} else if ($newVal === null) {
|
||||
$result[$this->getOwningTable($field)][$columnName] = null;
|
||||
} else {
|
||||
$result[$this->getOwningTable($field)][$columnName] = Type::getType(
|
||||
$this->_class->fieldMappings[$field]['type'])->convertToDatabaseValue($newVal, $platform);
|
||||
$this->_class->fieldMappings[$field]['type'])->convertToDatabaseValue($newVal, $platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +413,7 @@ class StandardEntityPersister
|
|||
return 'SELECT ' . $columnList . ' FROM ' . $this->_class->getTableName()
|
||||
. ' WHERE ' . $conditionSql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the preInsert event for the given entity.
|
||||
*
|
||||
|
@ -417,7 +426,7 @@ class StandardEntityPersister
|
|||
);
|
||||
$this->_evm->dispatchEvent(Events::preInsert, $eventArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the postInsert event for the given entity.
|
||||
*
|
||||
|
@ -427,7 +436,7 @@ class StandardEntityPersister
|
|||
{
|
||||
$this->_evm->dispatchEvent(Events::postInsert);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the preUpdate event for the given entity.
|
||||
*
|
||||
|
@ -440,7 +449,7 @@ class StandardEntityPersister
|
|||
);
|
||||
$this->_evm->dispatchEvent(Events::preUpdate, $eventArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the postUpdate event for the given entity.
|
||||
*
|
||||
|
|
|
@ -136,27 +136,29 @@ class UnitOfWork implements PropertyChangedListener
|
|||
*/
|
||||
private $_entityUpdates = array();
|
||||
|
||||
private $_extraUpdates = array();
|
||||
|
||||
/**
|
||||
* A list of all pending entity deletions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_entityDeletions = array();
|
||||
|
||||
|
||||
/**
|
||||
* All pending collection deletions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_collectionDeletions = array();
|
||||
|
||||
|
||||
/**
|
||||
* All pending collection creations.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_collectionCreations = array();
|
||||
|
||||
|
||||
/**
|
||||
* All collection updates.
|
||||
*
|
||||
|
@ -245,6 +247,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||
foreach ($commitOrder as $class) {
|
||||
$this->_executeUpdates($class);
|
||||
}
|
||||
// Extra updates that were requested by persisters.
|
||||
if ($this->_extraUpdates) {
|
||||
$this->_executeExtraUpdates();
|
||||
}
|
||||
|
||||
// Collection deletions (deletions of complete collections)
|
||||
foreach ($this->_collectionDeletions as $collectionToDelete) {
|
||||
|
@ -278,12 +284,22 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->_entityInsertions = array();
|
||||
$this->_entityUpdates = array();
|
||||
$this->_entityDeletions = array();
|
||||
$this->_extraUpdates = array();
|
||||
$this->_entityChangeSets = array();
|
||||
$this->_collectionUpdates = array();
|
||||
$this->_collectionDeletions = array();
|
||||
$this->_visitedCollections = array();
|
||||
}
|
||||
|
||||
protected function _executeExtraUpdates()
|
||||
{
|
||||
foreach ($this->_extraUpdates as $oid => $update) {
|
||||
list ($entity, $changeset) = $update;
|
||||
$this->_entityChangeSets[$oid] = $changeset;
|
||||
$this->getEntityPersister(get_class($entity))->update($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changeset for an entity.
|
||||
*
|
||||
|
@ -388,21 +404,19 @@ class UnitOfWork implements PropertyChangedListener
|
|||
private function _computeEntityChanges($class, $entity)
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
|
||||
if ( ! $class->isInheritanceTypeNone()) {
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
}
|
||||
|
||||
|
||||
$actualData = array();
|
||||
foreach ($class->reflFields as $name => $refProp) {
|
||||
if ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) {
|
||||
$actualData[$name] = $refProp->getValue($entity);
|
||||
}
|
||||
|
||||
if ($class->isCollectionValuedAssociation($name)
|
||||
&& $actualData[$name] !== null
|
||||
&& ! ($actualData[$name] instanceof PersistentCollection)
|
||||
) {
|
||||
if ($class->isCollectionValuedAssociation($name) && $actualData[$name] !== null
|
||||
&& ! ($actualData[$name] instanceof PersistentCollection)) {
|
||||
// If $actualData[$name] is Collection then unwrap the array
|
||||
if ($actualData[$name] instanceof Collection) {
|
||||
$actualData[$name] = $actualData[$name]->unwrap();
|
||||
|
@ -410,7 +424,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$assoc = $class->associationMappings[$name];
|
||||
// Inject PersistentCollection
|
||||
$coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName),
|
||||
$actualData[$name] ? $actualData[$name] : array());
|
||||
$actualData[$name] ? $actualData[$name] : array());
|
||||
$coll->setOwner($entity, $assoc);
|
||||
$coll->setDirty( ! $coll->isEmpty());
|
||||
$class->reflFields[$name]->setValue($entity, $coll);
|
||||
|
@ -527,7 +541,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->_originalEntityData[$oid] = $data;
|
||||
} else if ($state == self::STATE_DELETED) {
|
||||
throw DoctrineException::updateMe("Deleted entity in collection detected during flush."
|
||||
. " Make sure you properly remove deleted entities from collections.");
|
||||
. " Make sure you properly remove deleted entities from collections.");
|
||||
}
|
||||
// MANAGED associated entities are already taken into account
|
||||
// during changeset calculation anyway, since they are in the identity map.
|
||||
|
@ -609,12 +623,13 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$entityChangeSet = array_merge(
|
||||
$this->_entityInsertions,
|
||||
$this->_entityUpdates,
|
||||
$this->_entityDeletions);
|
||||
$this->_entityDeletions
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: We can cache computed commit orders in the metadata cache!
|
||||
// Check cache at this point here!
|
||||
|
||||
|
||||
// See if there are any new classes in the changeset, that are not in the
|
||||
// commit order graph yet (dont have a node).
|
||||
$newNodes = array();
|
||||
|
@ -622,9 +637,9 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$className = get_class($entity);
|
||||
if ( ! $this->_commitOrderCalculator->hasNodeWithKey($className)) {
|
||||
$this->_commitOrderCalculator->addNodeWithItem(
|
||||
$className, // index/key
|
||||
$this->_em->getClassMetadata($className) // item
|
||||
);
|
||||
$className, // index/key
|
||||
$this->_em->getClassMetadata($className) // item
|
||||
);
|
||||
$newNodes[] = $this->_commitOrderCalculator->getNodeForKey($className);
|
||||
}
|
||||
}
|
||||
|
@ -640,9 +655,9 @@ class UnitOfWork implements PropertyChangedListener
|
|||
// If the target class does not yet have a node, create it
|
||||
if ( ! $this->_commitOrderCalculator->hasNodeWithKey($targetClassName)) {
|
||||
$this->_commitOrderCalculator->addNodeWithItem(
|
||||
$targetClassName, // index/key
|
||||
$targetClass // item
|
||||
);
|
||||
$targetClassName, // index/key
|
||||
$targetClass // item
|
||||
);
|
||||
}
|
||||
// add dependency
|
||||
$otherNode = $this->_commitOrderCalculator->getNodeForKey($targetClassName);
|
||||
|
@ -657,7 +672,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
/**
|
||||
* Registers a new entity. The entity will be scheduled for insertion.
|
||||
* If the entity already has an identifier, it will be added to the identity map.
|
||||
*
|
||||
*
|
||||
* @param object $entity
|
||||
* @todo Rename to scheduleForInsert().
|
||||
*/
|
||||
|
@ -715,6 +730,11 @@ class UnitOfWork implements PropertyChangedListener
|
|||
}
|
||||
}
|
||||
|
||||
public function scheduleExtraUpdate($entity, array $changeset)
|
||||
{
|
||||
$this->_extraUpdates[spl_object_hash($entity)] = array($entity, $changeset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an entity is registered as dirty in the unit of work.
|
||||
* Note: Is not very useful currently as dirty entities are only registered
|
||||
|
@ -731,7 +751,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
/**
|
||||
* Registers a deleted entity.
|
||||
*
|
||||
*
|
||||
* @todo Rename to scheduleForDelete().
|
||||
*/
|
||||
public function registerDeleted($entity)
|
||||
|
@ -781,8 +801,8 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$oid = spl_object_hash($entity);
|
||||
$this->removeFromIdentityMap($entity);
|
||||
unset($this->_entityInsertions[$oid], $this->_entityUpdates[$oid],
|
||||
$this->_entityDeletions[$oid], $this->_entityIdentifiers[$oid],
|
||||
$this->_entityStates[$oid]);
|
||||
$this->_entityDeletions[$oid], $this->_entityIdentifiers[$oid],
|
||||
$this->_entityStates[$oid]);
|
||||
}
|
||||
|
||||
public function isEntityRegistered($entity)
|
||||
|
@ -832,12 +852,12 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$oid = spl_object_hash($entity);
|
||||
if ( ! isset($this->_entityStates[$oid])) {
|
||||
/*if (isset($this->_entityInsertions[$oid])) {
|
||||
$this->_entityStates[$oid] = self::STATE_NEW;
|
||||
} else if ( ! isset($this->_entityIdentifiers[$oid])) {
|
||||
// Either NEW (if no ID) or DETACHED (if ID)
|
||||
} else {
|
||||
$this->_entityStates[$oid] = self::STATE_DETACHED;
|
||||
}*/
|
||||
$this->_entityStates[$oid] = self::STATE_NEW;
|
||||
} else if ( ! isset($this->_entityIdentifiers[$oid])) {
|
||||
// Either NEW (if no ID) or DETACHED (if ID)
|
||||
} else {
|
||||
$this->_entityStates[$oid] = self::STATE_DETACHED;
|
||||
}*/
|
||||
if (isset($this->_entityIdentifiers[$oid]) && ! isset($this->_entityInsertions[$oid])) {
|
||||
$this->_entityStates[$oid] = self::STATE_DETACHED;
|
||||
} else {
|
||||
|
@ -918,10 +938,8 @@ class UnitOfWork implements PropertyChangedListener
|
|||
if ($idHash === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($this->_identityMap
|
||||
[$classMetadata->rootEntityName]
|
||||
[$idHash]);
|
||||
|
||||
return isset($this->_identityMap[$classMetadata->rootEntityName][$idHash]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -954,6 +972,11 @@ class UnitOfWork implements PropertyChangedListener
|
|||
foreach ($commitOrder as $class) {
|
||||
$this->_executeInserts($class);
|
||||
}
|
||||
// Extra updates that were requested by persisters.
|
||||
if ($this->_extraUpdates) {
|
||||
$this->_executeExtraUpdates();
|
||||
$this->_extraUpdates = array();
|
||||
}
|
||||
// remove them from _entityInsertions and _entityChangeSets
|
||||
$this->_entityInsertions = array_diff_key($this->_entityInsertions, $insertNow);
|
||||
$this->_entityChangeSets = array_diff_key($this->_entityChangeSets, $insertNow);
|
||||
|
@ -1035,7 +1058,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
/**
|
||||
* Deletes an entity as part of the current unit of work.
|
||||
*
|
||||
*
|
||||
* This method is internally called during delete() cascades as it tracks
|
||||
* the already visited entities to prevent infinite recursions.
|
||||
*
|
||||
|
@ -1092,7 +1115,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$id = $class->getIdentifierValues($entity);
|
||||
|
||||
if ( ! $id) {
|
||||
throw new InvalidArgumentException('New entity passed to merge().');
|
||||
throw new \InvalidArgumentException('New entity passed to merge().');
|
||||
}
|
||||
|
||||
$managedCopy = $this->tryGetById($id, $class->rootEntityName);
|
||||
|
@ -1134,7 +1157,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
/**
|
||||
* Cascades a merge operation to associated entities.
|
||||
*
|
||||
*
|
||||
* @param object $entity
|
||||
* @param object $managedCopy
|
||||
* @param array $visited
|
||||
|
@ -1237,34 +1260,34 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->_collectionUpdates = array();
|
||||
$this->_commitOrderCalculator->clear();
|
||||
}
|
||||
|
||||
|
||||
public function scheduleCollectionUpdate(PersistentCollection $coll)
|
||||
{
|
||||
$this->_collectionUpdates[] = $coll;
|
||||
}
|
||||
|
||||
|
||||
public function isCollectionScheduledForUpdate(PersistentCollection $coll)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
|
||||
public function scheduleCollectionDeletion(PersistentCollection $coll)
|
||||
{
|
||||
//TODO: if $coll is already scheduled for recreation ... what to do?
|
||||
// Just remove $coll from the scheduled recreations?
|
||||
$this->_collectionDeletions[] = $coll;
|
||||
}
|
||||
|
||||
|
||||
public function isCollectionScheduledForDeletion(PersistentCollection $coll)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
|
||||
public function scheduleCollectionRecreation(PersistentCollection $coll)
|
||||
{
|
||||
$this->_collectionRecreations[] = $coll;
|
||||
}
|
||||
|
||||
|
||||
public function isCollectionScheduledForRecreation(PersistentCollection $coll)
|
||||
{
|
||||
//...
|
||||
|
@ -1498,7 +1521,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->_originalEntityData[$oid] = $data;
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Clears the property changeset of the entity with the given OID.
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Doctrine\Tests\Models\ECommerce;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* ECommerceCart
|
||||
* Represents a typical cart of a shopping application.
|
||||
|
@ -40,7 +42,7 @@ class ECommerceCart
|
|||
|
||||
public function __construct()
|
||||
{
|
||||
$this->products = new \Doctrine\Common\Collections\Collection;
|
||||
$this->products = new Collection;
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Doctrine\Tests\Models\ECommerce;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* ECommerceCategory
|
||||
* Represents a tag applied on particular products.
|
||||
|
@ -42,8 +44,8 @@ class ECommerceCategory
|
|||
|
||||
public function __construct()
|
||||
{
|
||||
$this->products = new \Doctrine\Common\Collections\Collection();
|
||||
$this->children = new \Doctrine\Common\Collections\Collection();
|
||||
$this->products = new Collection();
|
||||
$this->children = new Collection();
|
||||
}
|
||||
|
||||
public function getId()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Doctrine\Tests\Models\ECommerce;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* ECommerceProduct
|
||||
* Represents a type of product of a shopping application.
|
||||
|
@ -45,8 +47,8 @@ class ECommerceProduct
|
|||
|
||||
public function __construct()
|
||||
{
|
||||
$this->features = new \Doctrine\Common\Collections\Collection;
|
||||
$this->categories = new \Doctrine\Common\Collections\Collection;
|
||||
$this->features = new Collection;
|
||||
$this->categories = new Collection;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
|
|
|
@ -13,8 +13,7 @@ namespace Doctrine\Tests\Models\ECommerce;
|
|||
class ECommerceShipping
|
||||
{
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
* @Id
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
|
|
|
@ -38,7 +38,9 @@ class AbstractManyToManyAssociationTestCase extends \Doctrine\Tests\OrmFunctiona
|
|||
|
||||
public function assertCollectionEquals(Collection $first, Collection $second)
|
||||
{
|
||||
if (count($first) != count($second)) {
|
||||
return $first->forAll(function($k, $e) use($second) { return $second->contains($e); });
|
||||
|
||||
/*if (count($first) != count($second)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($first as $element) {
|
||||
|
@ -46,6 +48,6 @@ class AbstractManyToManyAssociationTestCase extends \Doctrine\Tests\OrmFunctiona
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true;*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ class AllTests
|
|||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToManyBidirectionalAssociationTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManyUnidirectionalAssociationTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManyBidirectionalAssociationTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToManySelfReferentialAssociationTest');
|
||||
|
||||
return $suite;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ class OneToManySelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunctio
|
|||
$this->parent->addChild($this->secondChild);
|
||||
$this->_em->save($this->parent);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertForeignKeyIs($this->parent->getId(), $this->firstChild);
|
||||
$this->assertForeignKeyIs($this->parent->getId(), $this->secondChild);
|
||||
}
|
||||
|
@ -39,6 +41,7 @@ class OneToManySelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunctio
|
|||
public function testSavesAnEmptyCollection()
|
||||
{
|
||||
$this->_em->save($this->parent);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertEquals(0, count($this->parent->getChildren()));
|
||||
}
|
||||
|
@ -46,6 +49,7 @@ class OneToManySelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunctio
|
|||
public function testDoesNotSaveAnInverseSideSet() {
|
||||
$this->parent->brokenAddChild($this->firstChild);
|
||||
$this->_em->save($this->parent);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertForeignKeyIs(null, $this->firstChild);
|
||||
}
|
||||
|
@ -80,10 +84,10 @@ class OneToManySelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunctio
|
|||
|
||||
$this->assertTrue($children[0] instanceof ECommerceCategory);
|
||||
$this->assertSame($parent, $children[0]->getParent());
|
||||
$this->assertTrue(strstr($children[0]->getName(), ' books'));
|
||||
$this->assertEquals(' books', strstr($children[0]->getName(), ' books'));
|
||||
$this->assertTrue($children[1] instanceof ECommerceCategory);
|
||||
$this->assertSame($parent, $children[1]->getParent());
|
||||
$this->assertTrue(strstr($children[1]->getName(), ' books'));
|
||||
$this->assertEquals(' books', strstr($children[1]->getName(), ' books'));
|
||||
}
|
||||
|
||||
/* TODO: not yet implemented
|
||||
|
|
Loading…
Add table
Reference in a new issue