【问题标题】:Calling a service inside a lifecycle event在生命周期事件中调用服务
【发布时间】:2016-08-10 15:05:17
【问题描述】:

我有一个生命周期事件。创建订单后,prePersist 生命周期事件会在订单持久化到数据库之前向订单添加更多详细信息。

这是我的 prePersist 事件类;

<?php

namespace Qi\Bss\BaseBundle\Lib\PurchaseModule;

use Qi\Bss\BaseBundle\Entity\Business\PmodOrder;
use Doctrine\ORM\Event\LifecycleEventArgs;

/**
 * Listener class
 * Handles events related to list prices
 */
class OrderUserListener
{

    /**
     * Service container
     * @var type 
     */
    private $serviceContainer;

    /**
     * Performs tasks before destruction
     * @ORM\PrePersist
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $order = $args->getEntity();

        if ($order instanceof PmodOrder) {
            $user = $this->serviceContainer->get('security.token_storage')->getToken()->getUser();

            if ($user) {
                $order->setCreatedBy($user);
                $order->setCreatedAt(new \DateTime(date('Y-m-d H:i:s')));
                $order->setDepartment($user->getDepartment());
                $order->setStatus(PmodOrder::STATUS_AWAITING_APPROVAL);

                $this->serviceContainer->get('bss.pmod.order_logger')->log($order, 'Order Created');
            }
        }
    }

    /**
     * Sets the sales order exporter object
     * @param type $serviceContainer
     */
    public function setServiceContainer($serviceContainer)
    {
        $this->serviceContainer = $serviceContainer;
    }
}

它工作得很好,但这部分$this-&gt;serviceContainer-&gt;get('bss.pmod.order_logger')-&gt;log($order, 'Order Created'); 不想工作。我尝试在其中调用服务。我知道该服务在我的控制器中运行良好,但这里出现错误;

通过关系发现了一个新实体 'Qi\Bss\BaseBundle\Entity\Business\PmodLog#order' 不是 配置为实体级联持久化操作:Nuwe Test vir 记录器。要解决此问题:要么显式调用 EntityManager#persist() 在这个未知实体上或配置级联 例如,在映射中保留此关联 @ManyToOne(..,cascade={"persist"})。

这就是我的 OrderLogger 服务类的样子;

<?php

namespace Qi\Bss\BaseBundle\Lib\PurchaseModule;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Doctrine\ORM\EntityManager;
use Qi\Bss\BaseBundle\Entity\Business\PmodLog;

/**
 * Class AppLogger. Purchase Module logger.
 * @package FcConnectBundle\Lib
 */
class OrderLogger {

    private $em;
    private $tokenStorage;

    /**
     * Constructor.
     *
     * @param EntityManager $em
     * @param TokenStorage $securityTokenStorage
     */
    public function __construct(EntityManager $em, TokenStorage $securityTokenStorage)
    {
        $this->em = $em;
        $this->tokenStorage = $securityTokenStorage;
    }

    /**
     * Log an order action.
     *
     * @param string $text
     */
    public function log($order, $action)
    {
        $logRecord = new PmodLog();
        if (is_object($this->tokenStorage->getToken())) {
            $user = $this->tokenStorage->getToken()->getUser();
            if (is_object($user)) {
                $logRecord->setUser($user);
            }
        }
        $logRecord->setOrder($order);
        $logRecord->setAction($action);
        $logRecord->setTime(new \DateTime());

        $this->em->persist($logRecord);
        $this->em->flush();
    }

}

我已经尝试将日志中的持久性更改为合并,但这也不起作用。有人可以帮忙解释一下我做错了什么吗?

【问题讨论】:

  • 您的服务不应在 prePersist 事件中调用 $em-&gt;flush()
  • 不确定,但尝试将 $args-&gt;getEntityManager() 传递给 log 方法,而不是 EntityManager 的构造函数注入。
  • @Alsatian 我 100% 不懂,是否必须从我的服务中删除刷新?但是它在我调用相同服务的控制器中不起作用。我在控制器和 prePersist 事件中需要它。
  • 试试看。我不是 100% 确定 ;) 如果它解决了问题,你可以提供两种不同的服务,一个调用第二个 ...

标签: php symfony


【解决方案1】:

这不是最好的架构,但它会起作用:

在 prePersist 上将所有消息添加到某种私有变量(如 $logMessages),并添加另一个事件

/**
 * @param PostFlushEventArgs $args
 */
public function postFlush(PostFlushEventArgs $args)
{
    $logMessages = $this->logMessages;

    $this->logMessages = array(); //clean to avoid double logging

    if (!empty($logMessages)) {
        foreach ($logMessages as $message) {
            $this->serviceContainer->get('bss.pmod.order_logger')->log($message);
        }

    }
}

【讨论】:

    【解决方案2】:

    我通过添加 postPersist 并在其中而不是在我的 prePersist 中调用记录器来解决问题;

    /**
     * Performs tasks before destruction
     * @ORM\PostPersist
     */
    public function postPersist(LifecycleEventArgs $args)
    {
        $order = $args->getEntity();
    
        if ($order instanceof PmodOrder) {                
            $this->serviceContainer->get('bss.pmod.order_logger')->log($order, 'Order Created');
        }
    }
    

    因为我认为正在发生的事情是记录器试图被执行,但记录器中的顺序还不存在,因为它还没有持久化。这种方式对我来说更有意义,我认为这是最简单的解决方法。不过我可能是错的,欢迎对我的回答提出任何 cmet 和其他意见。

    【讨论】:

      猜你喜欢
      • 2017-12-10
      • 2016-12-03
      • 1970-01-01
      • 2015-04-21
      • 2023-01-22
      • 2014-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多