Récupérer l'ensemble des modifications d'une entité Doctrine après une mise à jour
Publié le 21/04/2021 • Actualisé le 21/04/2021
Dans ce bout de code, nous voyons comment récupérer l'ensemble des modifications d'une entité Doctrine après une mise à jour. C'est quelque chose d'essentiel à savoir quand on utilise Doctrine. Typiquement, après une mise à jour, on peut avoir besoin de déclencher certains traitements qui dépendent d'un statut ou d'une valeur modifiée. On peut lever un événement qui va déclencher tous les traitements voulus pour notre cas fonctionnel. Dans la seconde partie du snippet, on voit comment détecter le statut actuel de l'entité du point de vue de l'ORM.
<?php
declare(strict_types=1);
namespace App\Controller\Snippet;
use App\Data\ArticleData;
use App\Entity\Article;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\UnitOfWork;
/**
* J'utilise un trait PHP afin d'isoler chaque snippet dans un fichier.
* Ce code doit être apellé d'un contrôleur Symfony étendant AbstractController (depuis Symfony 4.2)
* ou Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
* Les services sont injectés dans le constructeur du contrôleur principal.
*
* @property ArticleData $articleData
* @property EntityManagerInterface $entityManager
*/
trait Snippet142Trait
{
public function snippet142(): void
{
// Get the current snippet
$snippet = $this->articleData->getArticleById(142);
// Get the unit of work object
$uow = $this->entityManager->getUnitOfWork();
// Modify a field
$snippet->setAuthor('Tintin'.random_int(1, 99));
// Compute all changesets
$uow->computeChangeSets();
// Or for this entity only
$uow->computeChangeSet($this->entityManager->getClassMetadata(Article::class), $snippet);
// Then get it, we have the field modified as the key which has for value
// an array with the old as first item and new value as the second item
// try it!
$changeset = $uow->getEntityChangeSet($snippet);
var_dump($changeset);
// And what is the state of this entity? 🧐
switch ($uow->getEntityState($snippet)) {
case UnitOfWork::STATE_MANAGED:
echo 'Snippet is managed (already in DB).';
break;
case UnitOfWork::STATE_REMOVED:
echo 'Snippet is going to be removed.';
break;
case UnitOfWork::STATE_DETACHED:
echo 'Snippet is detached.';
break;
case UnitOfWork::STATE_NEW:
echo 'Snippet is new.';
break;
}
// That's it! 😁
}
}
Exécuter le snippet ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫ Plus sur Stackoverflow Lire la doc Plus sur le web
<?php
declare(strict_types=1);
namespace App\Tests\Integration\Controller\Snippets;
use App\Data\ArticleData;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @see Snippet142Trait
*/
final class Snippet142Test extends KernelTestCase
{
private Registry $doctrine;
private ArticleData $articleData;
protected function setUp(): void
{
$this->doctrine = self::getContainer()->get('doctrine');
$this->articleData = self::getContainer()->get(ArticleData::class);
}
/**
* @see Snippet142Trait::snippet142
*/
public function testSnippet142(): void
{
$manager = $this->doctrine->getManager();
if (!$manager instanceof EntityManager) {
throw new \RuntimeException('Houston, We Have a Problem. 💥');
}
$uow = $manager->getUnitOfWork();
$snippet = $this->articleData->getArticleById(142);
$snippet->setAuthor('Tintin');
$uow->computeChangeSets();
$changeset = $uow->getEntityChangeSet($snippet);
self::assertIsArray($changeset);
self::assertArrayHasKey('author', $changeset);
self::assertSame('COil', $changeset['author'][0]);
self::assertSame('Tintin', $changeset['author'][1]);
}
}