ZF3 - 附加到 EventManager 的事件不会触发
ZF3 - An event attached to the EventManager does not trigger
我有一个 EntityRepository class,我想将一个事件附加到它的 "save" 方法。这是我设置事件管理器标识符的 AbstractRepository class:
abstract class AbstractRepository extends EntityRepository implements RepositoryInterface
{
/**
* @var EventManagerInterface
*/
protected $events;
/**
* Set the event manager instance used by this context.
*
* @param EventManagerInterface $events
*
* @return mixed
*/
public function setEventManager(EventManagerInterface $events)
{
$events->setIdentifiers([
__CLASS__,
get_class($this),
]);
$this->events = $events;
return $this;
}
/**
* Retrieve the event manager.
*
* Lazy-loads an EventManager instance if none registered.
*
* @return EventManagerInterface
*/
public function getEventManager()
{
if (!$this->events) {
$this->setEventManager(new EventManager());
}
return $this->events;
}
}
存储库 class 名为 DocumentRepository:
class DocumentsRepository extends AbstractRepository
{
public function save(Documents $entity)
{
$this->getEventManager()->trigger(RepositoryInterface::EVENT_BEFORE_SAVE);
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush($entity);
$this->getEventManager()->trigger(RepositoryInterface::EVENT_AFTER_SAVE);
return $entity;
}
}
还有一个定义事件名称的接口:
interface RepositoryInterface extends EventManagerAwareInterface
{
const EVENT_BEFORE_SAVE = 'before.save';
const EVENT_AFTER_SAVE = 'after.save';
}
为了注册监听器,我将以下代码添加到 module.php。
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
/* Register event listener(s) */
(new DocumentsRepositoryListener($serviceManager))->attach($eventManager);
}
最后,添加监听器 class:
class DocumentsRepositoryListener extends AbstractListener implements ListenerAggregateInterface
{
public function attach(EventManagerInterface $events, $priority = 1)
{
$sharedEvents = $events->getSharedManager();
$this->listeners[] = $sharedEvents
->attach(DocumentsRepository::class, RepositoryInterface::EVENT_BEFORE_SAVE, [$this, 'beforeSave']);
$this->listeners[] = $sharedEvents
->attach(DocumentsRepository::class, RepositoryInterface::EVENT_AFTER_SAVE, [$this, 'afterSave']);
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function beforeSave(EventInterface $event)
{
/* Something to do before saving */
}
public function afterSave(EventInterface $event)
{
/* Something to do after saving */
}
}
class AbstractListener 还包含一个用于注入 serviceLocator 和 setter/getter 方法的构造函数。
现在,我不知道为什么触发器不起作用。还有什么可以遗漏的吗!?
您编写的用于触发 DocumentsRepository
事件的代码没有问题。但是您对事件管理器的使用存在误解;特别是如何 附加 事件侦听器。
首先要说明的是,您已将存储库 class 设为 own EventManager
的实例; this 是您应该附加事件侦听器的实例。 Module::onBootstrap()
中的代码正在向 application 事件管理器注册,这是错误的实例。应用程序事件管理器处理应用程序事件,因此它永远不会触发您的自定义事件。
/* Register event listener(s) */
(new DocumentsRepositoryListener($serviceManager))->attach($eventManager);
将替换为:
$documentRepositoryListener->attach($repository->getEventManager());
注册监听器的逻辑可能更适合 RepositoryFactory
,例如:
class RepositoryFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$repository = new Repository();
if ($repository instanceof EventManagerAwareInterface) {
$eventManager = $repository->getEventManager();
$listener = $container->get('Foo/Event/Listener');
$listener->attach($eventManager);
}
return $repository;
}
}
最后,您还需要删除 DocumentsRepositoryListener::attach()
中的 $sharedEvents
用法;因为您想将事件侦听器附加到存储库事件管理器,这将是 $events
参数。
我有一个 EntityRepository class,我想将一个事件附加到它的 "save" 方法。这是我设置事件管理器标识符的 AbstractRepository class:
abstract class AbstractRepository extends EntityRepository implements RepositoryInterface
{
/**
* @var EventManagerInterface
*/
protected $events;
/**
* Set the event manager instance used by this context.
*
* @param EventManagerInterface $events
*
* @return mixed
*/
public function setEventManager(EventManagerInterface $events)
{
$events->setIdentifiers([
__CLASS__,
get_class($this),
]);
$this->events = $events;
return $this;
}
/**
* Retrieve the event manager.
*
* Lazy-loads an EventManager instance if none registered.
*
* @return EventManagerInterface
*/
public function getEventManager()
{
if (!$this->events) {
$this->setEventManager(new EventManager());
}
return $this->events;
}
}
存储库 class 名为 DocumentRepository:
class DocumentsRepository extends AbstractRepository
{
public function save(Documents $entity)
{
$this->getEventManager()->trigger(RepositoryInterface::EVENT_BEFORE_SAVE);
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush($entity);
$this->getEventManager()->trigger(RepositoryInterface::EVENT_AFTER_SAVE);
return $entity;
}
}
还有一个定义事件名称的接口:
interface RepositoryInterface extends EventManagerAwareInterface
{
const EVENT_BEFORE_SAVE = 'before.save';
const EVENT_AFTER_SAVE = 'after.save';
}
为了注册监听器,我将以下代码添加到 module.php。
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
/* Register event listener(s) */
(new DocumentsRepositoryListener($serviceManager))->attach($eventManager);
}
最后,添加监听器 class:
class DocumentsRepositoryListener extends AbstractListener implements ListenerAggregateInterface
{
public function attach(EventManagerInterface $events, $priority = 1)
{
$sharedEvents = $events->getSharedManager();
$this->listeners[] = $sharedEvents
->attach(DocumentsRepository::class, RepositoryInterface::EVENT_BEFORE_SAVE, [$this, 'beforeSave']);
$this->listeners[] = $sharedEvents
->attach(DocumentsRepository::class, RepositoryInterface::EVENT_AFTER_SAVE, [$this, 'afterSave']);
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function beforeSave(EventInterface $event)
{
/* Something to do before saving */
}
public function afterSave(EventInterface $event)
{
/* Something to do after saving */
}
}
class AbstractListener 还包含一个用于注入 serviceLocator 和 setter/getter 方法的构造函数。
现在,我不知道为什么触发器不起作用。还有什么可以遗漏的吗!?
您编写的用于触发 DocumentsRepository
事件的代码没有问题。但是您对事件管理器的使用存在误解;特别是如何 附加 事件侦听器。
首先要说明的是,您已将存储库 class 设为 own EventManager
的实例; this 是您应该附加事件侦听器的实例。 Module::onBootstrap()
中的代码正在向 application 事件管理器注册,这是错误的实例。应用程序事件管理器处理应用程序事件,因此它永远不会触发您的自定义事件。
/* Register event listener(s) */
(new DocumentsRepositoryListener($serviceManager))->attach($eventManager);
将替换为:
$documentRepositoryListener->attach($repository->getEventManager());
注册监听器的逻辑可能更适合 RepositoryFactory
,例如:
class RepositoryFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$repository = new Repository();
if ($repository instanceof EventManagerAwareInterface) {
$eventManager = $repository->getEventManager();
$listener = $container->get('Foo/Event/Listener');
$listener->attach($eventManager);
}
return $repository;
}
}
最后,您还需要删除 DocumentsRepositoryListener::attach()
中的 $sharedEvents
用法;因为您想将事件侦听器附加到存储库事件管理器,这将是 $events
参数。