EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

How to get the original entity before updating using BeforeEntityUpdatedEvent ?

Open wehostadm opened this issue 3 years ago • 2 comments

Hi,

I use the event BeforeEntityUpdatedEvent in order to detect changes with the entity before and after been updated.

However, using this code, I only be able to retrieve the entity updated even if the entity is not persist and flush yet...

public function onBeforeEntityUpdated(BeforeEntityUpdatedEvent $event): void
    {
        // EasyAdmin before EDIT action
        $entity = $event->getEntityInstance();
        \dump($entity);
        die();
    }

Can you help me ?

Thanks,

wehostadm avatar Jun 27 '22 19:06 wehostadm

Hi,

If you use Doctrine with entities, these informations are easily to determined :

        $uow = $this->em->getUnitOfWork();
        $uow->computeChangeSets();

        $changeset = $uow->getEntityChangeSet($entity);

The changeset result is an array with all fields who have changed with old and new value.

If you use collections, you need to check the changeset for each row.

dwd-akira avatar Jun 28 '22 14:06 dwd-akira

<?php

/**
 * Permet différentes vérifications sur une entité
 * 
 */

namespace App\Services;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\UnitOfWork;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;

class EntityCheckService
{

    /**
     * em
     *
     * @var EntityManagerInterface
     */
    private $em;

    /**
     * Construct
     *
     * @param EntityManagerInterface $entityManagerInterface
     */
    public function __construct(EntityManagerInterface $entityManagerInterface)
    {
        $this->em = $entityManagerInterface;
    }

    /**
     * Retourne TRUE si l'entité a été modifiée, sinon FALSE
     *
     * @param Object $entity
     * @return boolean
     */
    public function hasBeenChanged(Object $entity): bool
    {
        $uow = $this->em->getUnitOfWork();
        $uow->computeChangeSets();

        // pour tester les collections 
        $doctrineExtractor = new DoctrineExtractor($this->em);
        $propertyInfo = new PropertyInfoExtractor([$doctrineExtractor], [$doctrineExtractor]);

        return $this->recursiveHasBeenChanged($uow, $propertyInfo, $entity);
    }

    /**
     * Test recursif des collections
     * Retourne TRUE si l'entité a été modifiée, sinon FALSE
     * 
     * @param UnitOfWork $uow
     * @param PropertyInfoExtractor $propertyInfo
     * @param Object $entity
     * @return boolean
     */
    private function recursiveHasBeenChanged(UnitOfWork $uow, PropertyInfoExtractor $propertyInfo, Object $entity): bool
    {
        if ($uow->isScheduledForUpdate($entity)) {
            $uow->commit();
            return true;
        }

        // on test les collections
        // on récupère la liste et les types des propriétés  
        $properties = $propertyInfo->getProperties($entity::class);

        // on boucle les propriétés
        foreach ($properties as $property) {
            $propertyType = $propertyInfo->getTypes($entity::class, $property);
            if (empty($propertyType))
                continue;

            $type = $propertyType[0];

            // si ce n'est pas une collection on continue de boucler
            if (!$type->isCollection())
                continue;

            // le champ est une collection    
            // si la méthode n'existe pas on continue de boucler
            $method = 'get' . ucfirst($property);
            if (!method_exists($entity, $method))
                continue;

            // on test si des lignes sont supprimées
            $collection = $entity->$method();
            if (!empty($collection->getDeleteDiff()))
                return true;

            // on test les lignes de la collection
            foreach ($collection as $value) {
                // on test la ligne
                if ($uow->isScheduledForUpdate($value) || $uow->isScheduledForInsert($value)) {
                    $uow->commit();
                    return true;
                }
                // test récursif, si collections dans collections
                if ($this->recursiveHasBeenChanged($uow, $propertyInfo, $value))
                    return true;
            }
        }

        return false;
    }
}

dwd-akira avatar Jul 01 '22 23:07 dwd-akira