首页 文章

使用Symfony的EventDispatcher发射事件

提问于
浏览
0

我'm using 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

    我没办法引导应用程序,所以我所做的只是创建一个单例 EventManager ,有两个方法 registerListeners()fire(Event $event) ,然后我创建了一个bootstrap.php(解决方法),每个模块我 require once .

    在我的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的单挑 .

相关问题