如何在Symfony中以编程方式设置Doctrine实体侦听器



我有一个Symfony 3.4应用程序和一个Composer软件包,其中包含记录实体属性更改的EntityChangeListener。该包还包含一个 EntityListenerPass(编译器传递(,该 在生成服务容器时循环访问应用config.yml中定义的类名列表。它以编程方式标记实体类,如下所示,以通知侦听器preUpdate事件:

$listener = $container->getDefinition('entity_history.listener.entity_change');
$entities = $container->getExtensionConfig('entity_history')[0]['entities'];
foreach ($entities as $className) {
    $listener->addTag('doctrine.orm.entity_listener', ['entity' => $className, 'event' => 'preUpdate']);
}

添加这些标签会导致许多看起来不相关的错误。例如,实体状态的 Doctrine UnitOfWork 中未定义的索引错误。此外,从数据库加载的相关实体突然被Doctrine识别为实体。甚至 switch 语句中的对象比较也开始失败,并显示:

致命错误:嵌套级别太深 - 递归依赖?

但是没有这些听众,一切正常,所有测试都通过了。是否有另一种/更好的方法来以编程方式设置 Doctrine 实体侦听器?

是的,您可以通过直接对类元数据执行操作来附加实体侦听器。在我的应用程序(Symfony 2.8(中,我通过添加对loadClassMetadata事件做出反应的侦听器,为配置中标记的某些实体执行此操作。

使用这种方法,您可以在 Doctrine 首次加载类元时挂接实体侦听器(通过使用 addEntityListener (。因此,您只钩住当前上下文所需的实体侦听器,仅此而已。

这是我用来镜像它在特定情况下的外观的侦听器的修改版本:

namespace AppBundleListener;
use DoctrineORMEventLoadClassMetadataEventArgs;
class MappingListener
{
    private $listenerClassname;
    private $entities;
    public function __construct($listenerClassname, array $entities)
    {
        $this->entities = $entities;
        $this->listenerClassname = $listenerClassname;
    }
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        if(!in_array($classMetadata->name, $this->entities))
        {
            return;
        }
        // Hook the entity listener in the class metadata
        // $classMetadata->addEntityListener( string $eventName, string $class, string $method )
        $classMetadata->addEntityListener('preUpdate', $this->listenerClassName, 'preUpdate');
    }
}

然后在你的services.yml,像这样:

mapping.listener:
    class: AppBundleListenerMappingListener
    arguments: [ "%your_listener_classname%", "%your_entities_array%" ]
    tags:
        - { name: doctrine.event_listener, event: loadClassMetadata, lazy: true }

相关内容

  • 没有找到相关文章

最新更新