如何在不修改每个侦听器的服务工厂的情况下将侦听器附加到服务?

时间:2013-04-18 17:31:49

标签: dependencies zend-framework2 zend-framework-modules

我有一个非常简单的类,我把它放在模块Mail的服务配置中。

'factories' => array(
    'mailer' => function (ServiceLocatorInterface $sl) {
        return new \Project\Mail\Mailer();
    }
)

现在,Mailer使用EventManager来触发事件。我想附加一个监听器类,它会在Mailer发送电子邮件失败时记录错误,但是我想这样做而不是每次我修改Mailer有一个新的倾听者。

如何设置Mailer类,以便可以从其他模块连接侦听器?

2 个答案:

答案 0 :(得分:1)

您必须首先确定“Mailer无法发送电子邮件”的含义。如果您可以在Mailer课程中检查此情况,则必须触发相应的mail.error或类似事件。

然后,您必须将监听器附加到EventManager内的Mailer以侦听此mail.error事件并记录错误。

Mailer

内的触发错误

我们假设我们的Mailer类看起来像这样:

<?php
namespace Project\Mail;

class Mailer
{
    const EVENT_MAIL_ERROR = 'mail.error';

    protected $events;

    public function setEventManager(EventManagerInterface $events)
    {
        $this->events = $events;
        return $this;
    }

    public function getEventManager()
    {
        if ($this->events === null)
        {
            $this->setEventManager(new EventManager);
        }
        return $this->events;
    }

    public function send(MessageInterface $msg)
    {
        // try sending the message. uh-oh we failed!
        if ($someErrorCondition)
        {
            $this->getEventManager()->trigger(self::EVENT_MAIL_ERROR, $this, array(
                'custom-param' => 'failure reason',
            ));
        }
    }
}

听取事件

在引导期间,我们将监听器附加到EventManager内的Mailer

<?php
namespace FooBar;

use Zend\EventManager\Event;
use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $application = $event->getApplication();
        $services = $application->getServiceManager();
        $mailer = $services->get('Mailer');

        $mailer->getEventManager()->attach(Mailer::EVENT_MAIL_ERROR, function(Event $event)
        {
            $param = $event->getParam('custom-param');
            // log the error
        });
    }
}

有关实施细节,请参阅EventManager上的文档。

我希望这能解决你的问题!

答案 1 :(得分:0)

您无需在类触发事件中设置任何内容,只需要听取它们即可。

尽管@ user2257808的答案有效,但它并不是最有效的方法,因为从服务管理器获取邮件程序的行为会创建一个实例,即使在应用程序的其余部分中不需要它也是如此。

更好的方法是将您的侦听器附加到共享事件管理器,如果触发事件,将通知该事件管理器。

这样做与其他答案非常相似

public function onBootstrap(MvcEvent $event)
{
    $sharedEvents = $event->getApplication()->getEventManager()->getSharedManager();
    // listen to the 'someMailEvent' when triggered by the mailer
    $sharedEvents->attach('Project\Mail\Mailer', 'someMailEvent', function($e) {
         // do something for someMailEvent
    });
}

现在您不必担心邮件程序即使可用,但如果是,并且它触发了一个事件,您的收听者将会接收它。