Doctrine,从EntityManager中分离实体

时间:2017-10-18 19:27:45

标签: symfony doctrine-orm doctrine symfony-3.3

使用Doctrine,我想分离()一个实体。

在flush()之前,我使用:

$entityManager->detach($entity);

但是我的实体更新了 PersistentCollection 。此Collection位于UnitOfWork的getScheduledCollectionUpdates()中:

    foreach ($uow->getScheduledCollectionUpdates() as $col) {
        dump($col); // entity was here
    }

我想使用Collection(=删除所有更改)来分离所有实体。

修改:

这是我在 computeChangeSets() 之前的UnifOfWOrk:

enter image description here

我想分离PersistentCollection#1562。 Media#750 id已分离(Proxies__CG __ \ AppBundle \ Entity \ Media),但她的收藏品尚未分离。

这是Subscriber(用于保留所有版本的实体)。分离已在 copyEntity()中执行:

namespace AppBundle\EventListener;

use AppBundle\Annotation\Versionable;
use AppBundle\Annotation\VersionableField;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\PersistentCollection;
use Symfony\Component\PropertyAccess\PropertyAccess;

class DoctrineSubscriber implements EventSubscriber
{
    private $accessor;
    private $annotationReader;

    private $entitiesUpdated = [];

    public function __construct() {
    $this->accessor = PropertyAccess::createPropertyAccessor();
    $this->annotationReader = new AnnotationReader();
    }

    public function getSubscribedEvents()
    {
    return [
        'onFlush',
    ];
    }

    public function onFlush(OnFlushEventArgs $args)
    {
    $entityManager = $args->getEntityManager();
    $uow = $entityManager->getUnitOfWork();        

    if (!empty($uow->getScheduledEntityUpdates()) || !empty($uow->getScheduledCollectionUpdates())) {
        foreach ($uow->getIdentityMap() as $entities) {
            foreach ($entities as $entity) {
                $class = get_class($entity);                    

                $metaData = $entityManager->getClassMetadata($class);

                if (array_key_exists('versions', $metaData->associationMappings) && null !== $entity->getVersions()) {
                    $property = new \ReflectionProperty($metaData->getName(), 'versions');
                    $annotation = $this->annotationReader->getPropertyAnnotation($property, Versionable::class);
                    if ($annotation !== null) {
                        if (true === in_array($entity->getVersions()->last(), $uow->getScheduledEntityUpdates()) || true === $this->checkIfEntityIsUpdated($entityManager, $entity->getVersions()->last())) {
                            $entity->addVersion($this->copyEntity($entityManager, $entity->getVersions()->last()));
                            foreach ($entity->getVersions() as $version) {
                                if ($version !== $entity->getVersions()->last()) {
                                    $entity->getVersions()->removeElement($version);
                                    $entityManager->detach($version);
                                }
                            }
                        }
                    }
                }
            }
        }
    }        

    $uow->computeChangeSets();
    }

    public function checkIfEntityIsUpdated(EntityManager $entityManager, $entity)
    {
    if (in_array($entity, $this->entitiesUpdated)) {
        return true;
    }

    $uow = $entityManager->getUnitOfWork();

    if (in_array($entity, $uow->getScheduledEntityUpdates())) {
        $this->entitiesUpdated[] = $entity;
        return true;
    } else {
        $class = get_class($entity);            

        $metaData = $entityManager->getClassMetadata($class);

        $reflection = new \ReflectionClass($metaData->getName());
        foreach($reflection->getProperties() as $property) {
            $annotation = $this->annotationReader->getPropertyAnnotation($property, VersionableField::class);
            if ($annotation !== null) {
                if (array_key_exists($property->getName(), $metaData->associationMappings)) {
                    $value = $this->accessor->getValue($entity, $property->getName());

                    if ($value !== null) {
                        if($value instanceof PersistentCollection) {
                            if (in_array($value, $uow->getScheduledCollectionUpdates())) {
                                $this->entitiesUpdated[] = $value;
                                return true;
                            }
                        } else {
                            if (in_array($value, $uow->getScheduledEntityUpdates())) {
                                $this->entitiesUpdated[] = $value;
                                return true;
                            }

                            if (true === $this->checkIfEntityIsUpdated($entityManager, $value)) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
    }

    return false;
    }

    private function copyEntity(EntityManager $entityManager, $from)
    {
    $metaData = $entityManager->getClassMetadata(get_class($from));

    $toName = $metaData->getName();
    $to = new $toName;

    $reflection = new \ReflectionClass($metaData->getName());
    foreach($reflection->getProperties() as $property) {
        $annotation = $this->annotationReader->getPropertyAnnotation($property, VersionableField::class);
        if ($annotation !== null) {
            $value = $this->accessor->getValue($from, $property->getName());

            if (array_key_exists($property->getName(), $metaData->associationMappings)) {
                if($value instanceof PersistentCollection) {
                    if (in_array($value, $entityManager->getUnitOfWork()->getScheduledCollectionUpdates())) {
                        foreach ($value as $element) {
                            if (true === $this->checkIfEntityIsUpdated($entityManager, $element)) {
                                dump('CAS A PREVOIR mais pas sur quil soit différent du cas en dessous');
                                exit;
                            } else {
                                $newElement = $this->copyEntity($entityManager, $element);
                                if (isset($metaData->associationMappings[$property->getName()]['mappedBy'])) {
                                    $this->accessor->setValue($newElement, $metaData->associationMappings[$property->getName()]['mappedBy'], $to);
                                }
                                $this->accessor->getValue($to, $property->getName())->add($newElement);
                                $this->accessor->getValue($from, $property->getName())->removeElement($element);
                            }
                        }
                    }
                } elseif (null === $value) {
                    $this->accessor->setValue($to, $property->getName(), null);
                } else {
                    if (true === $this->checkIfEntityIsUpdated($entityManager, $value)) {
                        $this->accessor->setValue($to, $property->getName(), $this->copyEntity($entityManager, $value));
                    } else {
                        $this->accessor->setValue($to, $property->getName(), $value);
                    }
                }
            } else {
                $this->accessor->setValue($to, $property->getName(), $value);
            }                
        }
    }

    $entityManager->detach($from);
    $entityManager->persist($to);

    return $to;
    }
}

1 个答案:

答案 0 :(得分:0)

你在什么时候分开?如果您在doctrine onFlush listener或更高版本(preUpdate)中执行此操作,则已经计算了更改集。尝试在preFLush中执行此操作。或者,您可以通过调用

手动触发更改集的计算

$unitOfWork->computeChangeSets();

查看学说事件的更多详情here