简体   繁体   中英

Firing events using Symfony's EventDispatcher

I'm using Symfony's EventDispatcher component to trigger and handle events in my app, i have created a global helper function fire(Event $event) inside a Helpers.php file, which i autoload using 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);
            }
        }
    }

}

i use it like so : fire(new ExampleEvent('payload'));

This function is available everywhere in my app, Each time i call it the EventListeners in the $listeners array are registered then the $event is dispatched.

The issue is, I'm not sure if this is the best way to register and dispatch events, because for every call to this function the listeners have to be registered before the event is dispatched.

Should I register the listeners somewhere else then just fire the event inside the function, any ideas?

PS. I'm not using any framework.

I had no way to bootstrap the app, so all i did was create a singleton EventManager , with two methods registerListeners() and fire(Event $event) , then i created a bootstrap.php (work around), which i require once per module.

in my bootstrap.php :

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

EventManager singleton:

<?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);
            }
        }
    }
}

the helper function fire(Event $event) looks like this:

<?php

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

if (!function_exists('fire')) {

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

}

Thanks @Cerad for the heads-up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM