在Doctrine 2.4之前,捕获生命周期事件的默认方式(如prePersist
)是一个全局 event listener ,它将触发所有实体。运行像Symfony服务这样的监听器可以很容易地注入其他服务(如request
或request_stack
对象)。
现在更好的解决方案似乎是 entity listener ,因为这会带来更少的开销!
所以让我们在实体标题中开始这个......:
* @ORM\EntityListeners({ "AppBundle\Entity\Listener\LanguageListener" })
这是班级:
namespace AppBundle\Entity\Listener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class LanguageListener
{
public function prePersist($obj_entity, LifecycleEventArgs $obj_eventArgs)
{
$request = ???;
// set entity to users preferred language (for example 'de')
$obj_entity->setLanguage($request->getLocale());
}
}
正如您所看到的,我对如何访问Symfonys服务(在本例中为request
对象)没有任何想法。
但是等等!有一种方法:
global $kernel;
if ('AppCache' == get_class($kernel))
{
$kernel = $kernel->getKernel();
}
$request = $kernel->getContainer()->get('request');
它也在发挥作用。
但在我的所有研究中,我发现很多相关问题都严格警告了! 唯一区别:所有这些问题都是指实体,而不是实体监听器 ...
......引导我提出这两个问题:
[编辑:] 再次(请参阅第一句)让我明确指出这个问题也是关于如何不使用服务。服务需要一定的费用,请参阅Expensive Service Construction。特别是在这种情况下,我很少需要这些功能 - 这就是为什么我想要使用不作为服务运行的实体监听器。
对不起,我并没有过分强调这一方面。不知道为什么这有利于降低费率......
[Edit2:] 为了让事情变得更加清晰,我又添加了一个代码示例(第一个),展示了事物的映射方式。
答案 0 :(得分:6)
从doctrine/doctrine-bundle >= 1.5.0
开始,可以将实体侦听器创建为服务,如果用doctrine.orm.entity_listener
标记它们,它们将自动注册到the desired entity manager。您可以将所需的依赖项注入服务,例如请求堆栈。
创建一个监听器:
namespace AppBundle\Doctrine\Listener;
use Symfony\Component\HttpFoundation\RequestStack;
class LanguageListener
{
/**
* @var RequestStack
*/
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function prePersist($entity)
{
if (null !== $request = $this->requestStack->getCurrentRequest()) {
// put the logic here
}
}
}
将其注册为服务:
app.doctrine.language_listener:
class: AppBundle\Doctrine\Listener\LanguageListener
public: false
arguments: ["@request_stack"]
tags:
- { name: "doctrine.orm.entity_listener" }
注释实体:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as BaseUser;
/**
* @ORM\Entity()
* @ORM\EntityListeners("AppBundle\Doctrine\Listener\LanguageListener")
* @ORM\Table("user_")
*/
class User extends BaseUser
{
// ...
}
注意以这种方式注册的实体侦听器不会延迟加载,因此在创建实体管理器时将创建它们及其依赖项。
<强>更新强>
所以,如果你的问题是关于如何懒惰地使用它。我想到的第一个解决方案是将它声明为lazy service,但在这种情况下它实际上不能按预期工作,因为在注释中我们使用一个concrate类,它将在需要时由侦听器解析器创建,但在这种情况下,我们应该在注释中编写代理类名,以代替使用代理对象,这是不可能的。虽然有一个解决方案(目前没有记录),不注释具有@EntityListeners
的实体,但使用标记参数来注册监听器。像这样:
app.doctrine.language_listener:
class: AppBundle\Doctrine\Listener\LanguageListener
arguments: ["@request_stack"]
lazy: true
tags:
- { name: "doctrine.orm.entity_listener", entity: AppBundle\Entity\User, event: preUpdate }
- { name: "doctrine.orm.entity_listener", entity: AppBundle\Entity\User, event: postUpdate }
这样您就可以使用延迟服务,但它只适用于doctrine/orm >= 2.5.0
。
另一个解决方案是create an own entity listener resolver知道容器(这实际上不是一件好事),并在需要时使用它来获取监听器。有blog post方法可以做到这一点。