php – Symfony DI:与Doctrine事件订阅者的循环服务引用
| 
                         
 为了重构有关票证通知系统的代码,我创建了一个Doctrine侦听器: 
  
  
  
final class TicketNotificationListener implements EventSubscriber
{
    /**
     * @var TicketMailer
     */
    private $mailer;
    /**
     * @var TicketSlackSender
     */
    private $slackSender;
    /**
     * @var NotificationManager
     */
    private $notificationManager;
    /**
     * We must wait the flush to send closing notification in order to
     * be sure to have the latest message of the ticket.
     *
     * @var Ticket[]|ArrayCollection
     */
    private $closedTickets;
    /**
     * @param TicketMailer        $mailer
     * @param TicketSlackSender   $slackSender
     * @param NotificationManager $notificationManager
     */
    public function __construct(TicketMailer $mailer,TicketSlackSender $slackSender,NotificationManager $notificationManager)
    {
        $this->mailer = $mailer;
        $this->slackSender = $slackSender;
        $this->notificationManager = $notificationManager;
        $this->closedTickets = new ArrayCollection();
    }
    // Stuff...
} 
 目标是在使用Doctrine SQL通过邮件,Slack和内部通知创建或更新Ticket或TicketMessage实体时分派通知. 我已经与Doctrine有一个循环依赖问题,所以我从事件args中注入了实体管理器: class NotificationManager
{
    /**
     * Must be set instead of extending the EntityManagerDecorator class to avoid circular dependency.
     *
     * @var EntityManagerInterface
     */
    private $entityManager;
    /**
     * @var NotificationRepository
     */
    private $notificationRepository;
    /**
     * @var RouterInterface
     */
    private $router;
    /**
     * @param RouterInterface $router
     */
    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }
    /**
     * @param EntityManagerInterface $entityManager
     */
    public function setEntityManager(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        $this->notificationRepository = $this->entityManager->getRepository('AppBundle:Notification');
    }
    // Stuff...
} 
 经理从TicketNotificationListener注入 public function postPersist(LifecycleEventArgs $args)
{
    // Must be lazy set from here to avoid circular dependency.
    $this->notificationManager->setEntityManager($args->getEntityManager());
    $entity = $args->getEntity();
} 
 Web应用程序正在运行,但是当我尝试运行像doctrine:database:drop这样的命令时,我得到了这个: [SymfonyComponentDependencyInjectionExceptionServiceCircularReferenceException] Circular reference detected for service "doctrine.dbal.default_connection",path: "doctrine.dbal.default_connection -> mailer.ticket -> twig -> security.authorization_checker -> security.authentication.manager -> fos_user.user_provider.username_email -> fos_user.user_manager". 但这与供应商服务有关. 怎么解决这个?为什么我只在cli上出现此错误? 谢谢. 
 恕我直言,你在这里混合2个不同的概念: 
  
                          >域事件(例如TicketWasClosed) Doctrine的事件系统旨在挂钩持久化流程,处理与保存到数据库和从数据库加载直接相关的内容.它不应该用于其他任何事情. 对我来说,你想要发生的事情是: 
 这与Doctrine或一般的持久性无关.您需要的是另一个专门用于域事件的事件系统. 您仍然可以使用Doctrine中的EventManager,但请确保创建用于域事件的第二个实例. 你也可以用别的东西.例如Symfony的EventDispatcher.如果您正在使用Symfony框架,那么同样适用于此:不要使用Symfony的实例,为Domain Events创建自己的实例. 我个人喜欢SimpleBus,它使用对象作为事件而不是字符串(对象作为“参数”).它还遵循消息总线和中间件模式,它们提供了更多的自定义选项. PS:关于域事件有很多非常好的文章.谷歌是你的朋友:) 例 通常,域事件在对它们执行操作时会记录在实体本身中.因此Ticket实体将具有如下方法: public function close()
{
    // insert logic to close ticket here
    $this->record(new TicketWasClosed($this->id));
} 
 这可以确保实体对其状态和行为负全部责任,保护其不变量. 当然,我们需要一种方法将记录的域事件从实体中取出: /** @return object[] */
public function recordedEvents()
{
    // return recorded events
} 
 从这里我们可能想要两件事: >将这些事件收集到一个调度程序/发布者中. 使用Doctrine ORM,您可以订阅Doctrine的OnFlush事件的监听器,该事件将在所有刷新的实体(用于收集域事件)上调用recordedEvents(),而PostFlush可以将这些事件传递给调度程序/发布者(仅在成功时) . SimpleBus提供了一个提供此功能的DoctrineORMBridge. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!  | 
                  
