Symfony event subscriber

Egy példán keresztül event subscriberrel valósítjuk meg az adatbázisban történő változások loggolását.

Egy log táblába tesszük el a módosított entity-ket, amihez event subscribert használunk. A példában mysql és mongodb -be is elmentjük a logokat.

Event subscribert definiálhatjuk a service config jában a következő képpen:

config\services.yml:
 
services:
    ...
    App\EventSubscriber\DatabaseActivitySubscriber:
        tags:
            - { name: 'doctrine.event_subscriber' }

Az getSubscribedEvents -ben vesszük fel, hogy milyen eventekre iratkozunk fel. Amelyik meghívódik az után fog lefutni a mi kódunk. Saját eventeket is definiálhatunk, ha szükséges. A logAcitvity-ben, mi csak bejelentkezett userek műveleteit loggoljuk és csak a megadott entity-ket, nem az összeset, ez direkt állítható.

\EventSubscriber\DatabaseActivitySubscriber.php
 
<?php
// src/EventListener/DatabaseActivitySubscriber.php
namespace App\EventSubscriber;

use App\Entity\Logs;
use App\Document\Logs as LogDocument;
use App\Entity\Settings;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Events;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Doctrine\ODM\MongoDB\DocumentManager as DocumentManager;

class DatabaseActivitySubscriber implements EventSubscriber
{
    private $tokenStorage;
    private $em;
    private $dm;

    public function __construct(TokenStorageInterface $tokenStorage, EntityManagerInterface $em, DocumentManager $dm)
    {
        $this->tokenStorage = $tokenStorage;
        $this->em = $em;
        $this->dm = $dm;
    }

    public function getSubscribedEvents()
    {
        return [
            Events::postPersist,
            Events::preRemove,
            Events::postUpdate,
        ];
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        $this->logActivity('persist', $args);
    }

    public function preRemove(LifecycleEventArgs $args)
    {
        $this->logActivity('remove', $args);
    }

    public function postUpdate(LifecycleEventArgs $args)
    {
        $this->logActivity('update', $args);
    }

    private function logActivity(string $action, LifecycleEventArgs $args)
    {
        $entity = $args->getObject();

        $token = $this->tokenStorage->getToken();

        if (!$token) {
            return;
        }

        if (!$token->isAuthenticated()) {
            return;
        }

        if (!$user = $token->getUser()) {
            return;
        }

        $user = $token->getUser();
        $userId = $user->getId();

        $entityClasses = array(
            'App\Entity\Clients',
            'App\Entity\Tasks',
            'App\Entity\Items',
            'App\Entity\Settings',
            'App\Entity\Users',
            ...
        );

        if (in_array(get_class($entity), $entityClasses)) {

            $encoders = array(new XmlEncoder(), new JsonEncoder());
            $normalizers = array(new ObjectNormalizer());

            $serializer = new Serializer($normalizers, $encoders);
            $jsonContent = $serializer->serialize($entity, 'json');

            $log = new Logs();
            $log->setUserId($userId);
            $log->setDatetime(date("Y-m-d H:i:s"));
            $log->setAction($action);
            $log->setTableName(get_class($entity));
            $log->setDescription($jsonContent);

            $this->em->persist($log);
            $this->em->flush();

            $logDocument = new LogDocument();
            $logDocument->setUserId($userId);
            $logDocument->setDatetime(date("Y-m-d H:i:s"));
            $logDocument->setAction($action);
            $logDocument->setTableName(get_class($entity));
            $logDocument->setDescription($jsonContent);

            $this->dm->persist($logDocument);
            $this->dm->flush();
        }
    }
}

Olvasnivaló:
https://symfony.com/doc/current/event_dispatcher.html#listeners-or-subscribers
https://symfony.com/doc/current/components/event_dispatcher.html
 
2019.10.12.