【问题标题】:Symfony & Doctrine: Log changes in a table with an Event ListenerSymfony & Doctrine:使用事件监听器记录表中的更改
【发布时间】:2017-06-19 22:25:29
【问题描述】:

在 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”的最大函数嵌套级别, 中止!在 /var/www/sellbytel/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php 在第 187 行

所以我的问题是:如果可能的话,我如何从 EventListener 保存数据库中的更改?如果没有,是否有解决方法来创建此日志?

【问题讨论】:

  • 恕我直言,您不能使用onFlush 事件来定义您需要处理的更改数组,而不是在postFlush 处理这些更改后重新开始整个过程​​。您可以尝试使用 preUpdatepostUpdate 事件手动保存新旧值,而不是依赖 unitOfWork。
  • Loggable behaviour for Doctrine2 可能对你有用。

标签: php symfony doctrine-orm


【解决方案1】:

如果User 的用户名或密码字段发生更改,则日志将写入UserAudit 表,因此与数据库触发器的逻辑相同。您可以根据自己的需要进行调整。

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

services.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();
        }
    }
}

【讨论】:

    猜你喜欢
    • 2016-10-23
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多