使用Symfony的EventDispatcher触发事件

时间:2018-06-24 11:04:12

标签: php symfony events

我正在使用Symfony的EventDispatcher组件来触发和处理应用程序中的事件,我已经在Helpers.php文件中创建了一个全局帮助程序功能fire(Event $event),我可以使用composer自动加载该功能。

Helpers.php

<?php

use App\Http\Helpers\ConfigManager;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;

//listeners array defined in another file.
$listeners = [
    [\App\Events\ExampleEvent::class => \App\Listeners\ExampleListener::class], 
    [\App\Events\JobEvent::class => \App\Listeners\JobEventListener::class]
];

if (!function_exists('fire')) {

    function fire(Event $event) {
        $dispatcher = new EventDispatcher();
        $listeners  = ConfigManager::getInstance()->getEventListeners();

        foreach ($listeners as $listener) {
            foreach ($listener as $ev => $handler) {
                $instance = new $handler;
                if (method_exists($instance, 'handle')) {
                    $dispatcher->addListener($ev, [$instance, 'handle']);
                }
            }
        }

        //events should be dispatched once
        //remove duplicate events name from events array.
        $events = array_unique(
                      array_map(function ($listener) {
                          return array_keys($listener)[0]; 
                      }, $listeners)
                  );

        foreach ($events as $ev) {
            if ($event instanceof $ev) {
                $dispatcher->dispatch($ev, $event);
            }
        }
    }

}

我这样使用它:fire(new ExampleEvent('payload'));

此函数在我的应用程序中随处可见,每次调用它时,都会注册$ listeners数组中的EventListeners,然后调度$ event。

问题是,我不确定这是否是注册和调度事件的最佳方法,因为对于此函数的每次调用,侦听器都必须在调度事件之前进行注册。

我应该在其他地方注册侦听器,然后在函数内部触发事件,有什么想法吗?

PS。我没有使用任何框架。

1 个答案:

答案 0 :(得分:0)

我无法引导应用程序,所以我要做的就是创建一个EventManagerregisterListeners()两个方法的单例fire(Event $event),然后我创建了bootstrap.php(工作左右),每个模块我需要一次

在我的bootstrap.php中:

EventManager::getInstance()->registerListeners();

EventManager单例:

<?php

namespace App\Http\Helpers;


use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;

class EventManager
{
    private $dispatcher = null;

    private $listeners = null;

    protected function __construct()
    {
        $this->dispatcher = new EventDispatcher();
        $this->listeners = ConfigManager::getInstance()->getEventListeners();
    }

    private function __clone() {} //nah, no clones.

    public static function getInstance()
    {
        static $instance = null;
        if ($instance === null) {
            $instance = new EventManager();
        }
        return $instance;
    }

    public function registerListeners()
    {
        foreach ($this->listeners as $listener) {
            foreach ($listener as $ev => $handler) {
                $instance = new $handler;
                if (method_exists($instance, 'handle')) {
                    $this->dispatcher->addListener($ev, [$instance, 'handle']);
                }
            }
        }
    }

    public function fire(Event $event)
    {
        //events should be dispatched once, remove duplicate event name from events array.
        $events = array_unique(array_map(function ($listener) { return array_keys($listener)[0]; }, $this->listeners));

        foreach ($events as $ev) {
            if ($event instanceof $ev) {
                $this->dispatcher->dispatch($ev, $event);
            }
        }
    }
}

辅助函数fire(Event $event)如下所示:

<?php

use App\Http\Helpers\EventManager;
use Symfony\Component\EventDispatcher\Event;

if (!function_exists('fire')) {

    function fire(Event $event) {
        EventManager::getInstance()->fire($event);
    }

}

感谢@Cerad的单挑。