Php 如何惰性地创建实体侦听器并向其中注入依赖项
在条令2.4之前,捕获生命周期事件的默认方法(如Php 如何惰性地创建实体侦听器并向其中注入依赖项,php,symfony,doctrine-orm,entitylisteners,Php,Symfony,Doctrine Orm,Entitylisteners,在条令2.4之前,捕获生命周期事件的默认方法(如prePersist)是一个全局,它将为所有实体触发。将这样的侦听器作为Symfony服务运行可以轻松地注入其他服务(如request或request\u堆栈对象) 现在更好的解决方案似乎是,因为这样会大大减少开销 让我们从实体标题开始…: * @ORM\EntityListeners({ "AppBundle\Entity\Listener\LanguageListener" }) 下面是课程: namespace AppBundle\Enti
prePersist
)是一个全局,它将为所有实体触发。将这样的侦听器作为Symfony服务运行可以轻松地注入其他服务(如request
或request\u堆栈
对象)
现在更好的解决方案似乎是,因为这样会大大减少开销
让我们从实体标题开始…:
* @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服务(在本例中为请求
对象)
但是等等!有一种方法:
global $kernel;
if ('AppCache' == get_class($kernel))
{
$kernel = $kernel->getKernel();
}
$request = $kernel->getContainer()->get('request');
它也在起作用
但在我所有的研究中,我发现了很多相关的问题,这些问题都是严格警告我的!
唯一的区别是:所有这些问题都是针对实体的,而不是针对实体听众的
。。。让我来回答这两个问题:
[编辑:再次(见第一句话)让我澄清一下,这个问题也是关于如何不使用服务的。服务是有成本的,请参阅。特别是在这种情况下,我很少需要该功能——这就是为什么我希望使用不作为服务运行的实体侦听器 对不起,我没有过分强调这一方面。不知道为什么这有资格降低利率
[Edit2::为了让事情更清楚,我又添加了一个代码示例(第一个)这显示了事物是如何映射的。自
条令/条令包>=1.5.0
实体侦听器可以创建为服务,如果它们被标记为条令.orm.entity\u侦听器
,它们将自动注册到。您可以将所需的依赖项注入服务,例如请求堆栈
创建侦听器:
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
{
// ...
}
请注意以这种方式注册的实体侦听器不会延迟加载,因此在创建实体管理器时将创建它们及其依赖项
更新:
所以如果你的问题是关于如何懒散地使用它。我想到的第一个解决方案是将其声明为,但在本例中,它实际上没有按预期工作,因为在注释中,我们使用了一个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 }
通过这种方式,您可以使用惰性服务,但它仅适用于原则/orm>=2.5.0
另一个解决方案是了解容器(这实际上不是一件好事),并在需要时使用它获取侦听器。有一种方法可以做到这一点。您已经看到了吗?我认为这是与symfony方法结合使用的解决方案,我还没有真正掌握解析器的概念。今天早些时候读到过,好书:但无论如何,这仍然不能解决我的问题。据我所知,让服务接受容器作为参数被认为是不好的做法。你应该通过你需要的服务@Matteo的方法是Eddie应该做的,以使事情顺利进行。谢谢你简洁的回答!但这并不是我问题的答案:我很清楚我可以使用一个服务并注入一切(以及它是如何完成的)。但这正是我想要避免的。看到新的编辑和我在原始问题中的第一句话,我真的不明白你想在这里实现什么。这是一个监听用户实体事件的实体侦听器。应该这样做。如果您不想手动实例化它,那么您必须执行与容器现在所做的相同的操作。您必须尽快将其注册到实体管理器中,以捕获所需的事件。您可以尝试将其定义为代理,以便创建代理(但这需要“symfony/proxy-manager桥”)或创建工厂。我看到我的上述解决方案正在工作:仅在需要时加载和调用它。既然这是教义,就不能完全错,对吧?唯一的问题是如何以正确的方式访问
请求
服务。听起来很有希望!“好吧,我看到我上面的解决方案正在工作:它只在需要时加载和调用”。。。那不是真的。。。如何将侦听器注册到EM中?每一个请求你都必须这样做。顺便说一句,您应该记住,这种方法只适用于web环境,而不适用于控制台命令,因为那里没有请求。