为什么自定义用户事件侦听器会停止事件传播?

时间:2015-08-26 04:44:51

标签: symfony fosuserbundle

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

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

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

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

FOS用户捆绑文档的含义不明确。虽然它们似乎从代码示例here暗示自定义事件会停止正常传播,或者至少替换给定事件的正常操作。

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

那么User Bundle自定义事件监听器阻止传播到内置的正常事件吗?如果是的话,那还有吗?因此,不需要修改请求或响应的自定义代码可以简单地监听事件,而不会影响用户捆绑包附带的正常操作。

2 个答案:

答案 0 :(得分:1)

回答我自己的问题:

FOS用户捆绑包自定义事件侦听器对捆绑包附带的事件没有任何影响。他们将按照您对阅读symfony文档的期望进行处理和运行。

值得注意的是,我在上面引用的用户捆绑文档对于自定义事件应该用于什么而言有点波动。如果在调度“pre-action”事件之后检查调度每个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对象,然后控制器将其用作操作的返回值 - 将最终用户重定向到您选择的URL。

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

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

答案 1 :(得分:0)

我之前的答案中提到的symfony bug已在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 }