1
0
mirror of synced 2025-02-02 13:31:45 +03:00

#6613 #6614 ensuring that only newly added items that weren't loaded are restored in the dirty state of the collection

This commit is contained in:
Marco Pivetta 2017-08-11 15:13:39 +02:00
parent 49694dc335
commit 5521d1f325
No known key found for this signature in database
GPG Key ID: 4167D3337FD9D629

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM; namespace Doctrine\ORM;
use Closure;
use Doctrine\Common\Collections\AbstractLazyCollection; use Doctrine\Common\Collections\AbstractLazyCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@ -685,23 +684,41 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
protected function doInitialize() protected function doInitialize()
{ {
// Has NEW objects added through add(). Remember them. // Has NEW objects added through add(). Remember them.
$newObjects = array(); $newlyAddedDirtyObjects = array();
if ($this->isDirty) { if ($this->isDirty) {
$newObjects = $this->collection->toArray(); $newlyAddedDirtyObjects = $this->collection->toArray();
} }
$this->collection->clear(); $this->collection->clear();
$this->em->getUnitOfWork()->loadCollection($this); $this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot(); $this->takeSnapshot();
// Reattach NEW objects added through add(), if any. if ($newlyAddedDirtyObjects) {
if ($newObjects) { $this->restoreNewObjectsInDirtyCollection($newlyAddedDirtyObjects);
foreach ($newObjects as $obj) {
$this->collection->add($obj);
} }
}
/**
* @param object[] $newObjects
*
* @return void
*
* Note: the only reason why this entire looping/complexity is performed via `spl_object_hash`
* is because we want to prevent using `array_udiff()`, which is likely to cause very
* high overhead (complexity of O(n^2)). `array_diff_key()` performs the operation in
* core, which is faster than using a callback for comparisons
*/
private function restoreNewObjectsInDirtyCollection(array $newObjects)
{
$loadedObjects = $this->collection->toArray();
$newObjectsByOid = array_combine(array_map('spl_object_hash', $newObjects), $newObjects);
$loadedObjectsByOid = array_combine(array_map('spl_object_hash', $loadedObjects), $loadedObjects);
$newObjectsThatWereNotLoaded = array_diff_key($newObjectsByOid, $loadedObjectsByOid);
// Reattach NEW objects added through add(), if any.
array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']);
$this->isDirty = true; $this->isDirty = true;
} }
}
} }