簡體   English   中英

Symfony 和 Doctrine:使用事件偵聽器記錄表中的更改

[英]Symfony & Doctrine: Log changes in a table with an Event Listener

在 Symfony 3 項目中,我有一個實體,我想審核某些屬性的更改,因此我可以創建一個事件偵聽器來存儲它們。

該實體或多或少如下:

  • ReceivedEmail: agent 和 caseDetail 是我要審計的屬性
  • ReceivedEmailChange:previousAgent、currentAgent 和 previousCaseDetail 和 currentCaseDetail

EventListener 如下所示

    /**
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        /** @var ReceivedEmail $entity */
        $entityManager = $args->getEntityManager();
        $unitOfWork = $entityManager->getUnitOfWork();

        $updates = $unitOfWork->getScheduledEntityUpdates();

        foreach ($updates as $entity) {

            if ($entity instanceof ReceivedEmail) {

                $changes = $unitOfWork->getEntityChangeSet($entity);

                $this->receivedEmailChanges[] = $this->receivedEmailChangeManager
                    ->getReceivedEmailChanges($entity, $changes);
            }
        }
    }

public function postFlush(PostFlushEventArgs $args)
    {
        $em = $args->getEntityManager();

        $i = 0;
        foreach($this->receivedEmailChanges as $receivedEmailChange) {
            $em->persist($receivedEmailChange);
            unset($this->receivedEmailChanges[$i]);
            $i++;
        }

        if ($i > 0) {
            $em->flush();
        }
    }

問題是在 postFlush 方法上調用 $entityManager->flush() 以無限循環結束,並且出現此錯誤:

PHP 致命錯誤:達到“256”的最大函數嵌套級別,正在中止! 在第 187 行的 /var/www/sellbytel/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php

所以我的問題是:如果可能的話,如何從 EventListener 保存數據庫中的更改? 如果沒有,是否有創建此日志的解決方法?

如果User username 或 password 字段發生更改,日志將寫入UserAudit表,因此與數據庫觸發器的邏輯相同。 您可以根據自己的需要進行調整。

參考: http : //www.inanzzz.com/index.php/post/ew0r/logging-field-changes-with-a-trigger-like-event-listener-for-auditing-purposes

服務.yml

services:
    application_backend.event_listener.user_entity_audit:
        class: Application\BackendBundle\EventListener\UserEntityAuditListener
        arguments: [ @security.context ]
        tags:
            - { name: doctrine.event_listener, event: preUpdate }
            - { name: doctrine.event_listener, event: postFlush }

聽眾

namespace Application\BackendBundle\EventListener;

use Application\BackendBundle\Entity\User;
use Application\BackendBundle\Entity\UserAudit;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Symfony\Component\Security\Core\SecurityContextInterface;

class UserEntityAuditListener
{
    private $securityContext;
    private $fields = ['username', 'password'];
    private $audit = [];

    public function __construct(SecurityContextInterface $securityContextInterface)
    {
        $this->securityContext = $securityContextInterface;
    }

    public function preUpdate(PreUpdateEventArgs $args) // OR LifecycleEventArgs
    {
        $entity = $args->getEntity();

        if ($entity instanceof User) {
            foreach ($this->fields as $field) {
                if ($args->getOldValue($field) != $args->getNewValue($field)) {
                    $audit = new UserAudit();
                    $audit->setField($field);
                    $audit->setOld($args->getOldValue($field));
                    $audit->setNew($args->getNewValue($field));
                    $audit->setUser($this->securityContext->getToken()->getUsername());

                    $this->audit[] = $audit;
                }
            }
        }
    }

    public function postFlush(PostFlushEventArgs $args)
    {
        if (! empty($this->audit)) {
            $em = $args->getEntityManager();

            foreach ($this->audit as $audit) {
                $em->persist($audit);
            }

            $this->audit = [];
            $em->flush();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM