【问题标题】:Why do custom User Event listeners stop event propagation?为什么自定义用户事件侦听器会停止事件传播?
【发布时间】:2015-08-26 04:44:50
【问题描述】:

我正在尝试使用自定义事件侦听器连接到 Friends of Symfony User Bundle 事件。有许多为 FOS 用户包创建事件侦听器的示例,我在创建侦听器、接收事件和执行我的自定义代码方面都没有遇到任何问题。我正在监听 FOSUserEvents::REGISTRATION_CONFIRMED 事件并发送一些关于新确认用户的通知电子邮件。

但我的方法存在一个问题。即:

如果没有我的事件监听器,用户会在访问确认页面后登录并重定向到他们的个人资料页面。但是,我的事件侦听器的存在停止了正常的事件传播,并且用户没有登录或重定向离开确认页面。

这是预期的行为吗?我在文档中看到了相互矛盾的信息。

FOS 用户捆绑文档在这一点上模棱两可。尽管它们似乎从代码示例 here 中暗示自定义事件停止正常传播,或者至少替换给定事件的正常操作。

虽然 Symfony 事件文档 here 描述了用于阻止事件传播的 stopPropagation 函数,但仅在必要时。

那么 User Bundle 自定义事件侦听器会阻止传播到内置的正常事件吗?如果是的话,这周围还有吗?所以不需要修改请求或响应的自定义代码可以简单的监听事件,不会影响User Bundle自带的正常动作。

【问题讨论】:

    标签: symfony fosuserbundle


    【解决方案1】:

    回答我自己的问题:

    FOS 用户捆绑包自定义事件侦听器对捆绑包附带的事件侦听器没有影响。它们都将按照您阅读 symfony 文档时所期望的那样被处理和运行。

    值得注意的是,我在上面引用的 User Bundle 文档对于自定义事件应该用于什么内容有点手忙脚乱。如果您检查发送每个events 的用户包中的控制器代码 - 在发送“预操作”事件并处理事件侦听器(包括您注册的任何自定义侦听器)之后,控制器会检查事件对象提取控制操作完成方式的特定属性。在example given in the documentation 中,RESETTING_RESET_SUCCESS 事件的自定义侦听器使用event->setResponse。这是ResettingController中resetAction的相关代码部分:

    $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);
    
    $userManager->updateUser($user);
    
    if (null === $response = $event->getResponse()) {
        $url = $this->container->get('router')->generate('fos_user_profile_show');
        $response = new RedirectResponse($url);
    }
    
    $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
    
    return $response;
    

    自定义侦听器可以做的唯一一件事是在事件中返回一个 RedirectResponse 对象,然后控制器将使用该对象作为操作的返回值 - 将最终用户重定向到您选择的网址。

    所以最后一个谜是为什么我在 REGISTRATION_CONFIRMED 事件上的自定义事件侦听器在访问电子邮件确认链接后破坏了自动登录。该问题的根本原因是 Symfony 本身的一个令人讨厌的竞争条件错误。该错误已于去年年底修复,但我正在开发客户的应用程序,他们仍在运行具有该错误的旧版本的 symfony。简而言之,使用 swiftmailer 发送电子邮件, 将电子邮件假脱机到内存中,可能会导致在写出会话文件之前返回 HTTP 响应的竞争。随后重定向到客户端将导致他们加载较旧的 - 未登录的 - 会话文件,从而看起来没有登录以进行下一页加载。

    我将在第二个答案中发布有关错误的详细信息,因为堆栈溢出显然害怕一个答案中的链接太多。

    【讨论】:

      【解决方案2】:

      我之前的回答中提到的 symfony 错误已在 2.3.22、2.5.7 和 2.6 及更高版本中修复。如果您对此感到好奇,这里有 github 问题:

      错误报告:https://github.com/symfony/symfony/issues/6417

      修复: https://github.com/symfony/symfony/pull/12341

      如果您无法将 symfony 升级到固定版本,解决方法是停止 swiftmailer 假脱机到内存(即在响应返回到浏览器之前立即发送)。在您的 swiftmailer 配置中注释掉这一行:

      #    spool:     { type: memory }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-21
        • 2018-07-26
        • 2011-03-31
        • 1970-01-01
        • 2016-07-24
        • 2022-01-02
        • 1970-01-01
        • 2016-09-23
        相关资源
        最近更新 更多