PHP - Create your own PHP PSR-14 event dispatcher

fadymr

F.R Michel

Posted on January 10, 2021

PHP - Create your own PHP PSR-14 event dispatcher

PHP Event Dispatcher PSR-14

Create an Event dispatcher is very easy

Install the standard interfaces for event handling.:

composer require psr/event-dispatcher
Enter fullscreen mode Exit fullscreen mode

Create EventDispatcher class to disptach event

<?php

namespace DevCoder\Listener;

use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\EventDispatcher\ListenerProviderInterface;
use Psr\EventDispatcher\StoppableEventInterface;

/**
 * Class EventDispatcher
 */
class EventDispatcher implements EventDispatcherInterface
{
    /**
     * @var ListenerProviderInterface
     */
    private $listenerProvider;

    /**
     * EventDispatcher constructor.
     * @param ListenerProviderInterface $listenerProvider
     */
    public function __construct(ListenerProviderInterface $listenerProvider)
    {
        $this->listenerProvider = $listenerProvider;
    }

    /**
     * @param object $event
     * @return object
     */
    public function dispatch(object $event): object
    {

        if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
            return $event;
        }
        foreach ($this->listenerProvider->getListenersForEvent($event) as $listener) {
            $listener($event);
        }
        return $event;
    }
}
Enter fullscreen mode Exit fullscreen mode

Create ListenerProvider class to sorage all listener

<?php


namespace DevCoder\Listener;


use Psr\EventDispatcher\ListenerProviderInterface;

/**
 * Class ListenerProvider
 * @package DevCoder\Listener
 */
class ListenerProvider implements ListenerProviderInterface
{

    /**
     * @var array
     */
    private $listeners = [];

    /**
     * @param object $event
     *   An event for which to return the relevant listeners.
     * @return iterable[callable]
     *   An iterable (array, iterator, or generator) of callables.  Each
     *   callable MUST be type-compatible with $event.
     */
    public function getListenersForEvent(object $event): iterable
    {
        $eventType = get_class($event);
        if (array_key_exists($eventType, $this->listeners)) {
            return $this->listeners[$eventType];
        }

        return [];
    }

    /**
     * @param string $eventType
     * @param callable $callable
     * @return $this
     */
    public function addListener(string $eventType, callable $callable): self
    {
        $this->listeners[$eventType][] = $callable;
        return $this;
    }

    /**
     * @param string $eventType
     */
    public function clearListeners(string $eventType): void
    {
        if (array_key_exists($eventType, $this->listeners)) {
            unset($this->listeners[$eventType]);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Create Event class

<?php

namespace DevCoder\Listener;

use Psr\EventDispatcher\StoppableEventInterface;

/**
 * Class Event
 * @package DevCoder\Listener
 */
class Event implements StoppableEventInterface
{
    /**
     * @var bool Whether no further event listeners should be triggered
     */
    private $propagationStopped = false;

    /**
     * Is propagation stopped?
     *
     * This will typically only be used by the Dispatcher to determine if the
     * previous listener halted propagation.
     *
     * @return bool
     *   True if the Event is complete and no further listeners should be called.
     *   False to continue calling listeners.
     */
    public function isPropagationStopped(): bool
    {
        return $this->propagationStopped;
    }

    /**
     * Stops the propagation of the event to further event listeners.
     *
     * If multiple event listeners are connected to the same event, no
     * further event listener will be triggered once any trigger calls
     * stopPropagation().
     */
    public function stopPropagation(): void
    {
        $this->propagationStopped = true;
    }
}
Enter fullscreen mode Exit fullscreen mode

Create an Event

<?php


namespace App\Event;

use App\Entity\User;
use DevCoder\Listener\Event;

/**
 * Class PreCreateEvent
 * @package App\Event
 */
class PreCreateEvent extends Event
{

    /**
     * @var object
     */
    private $object;

    /**
     * PreCreateEvent constructor.
     * @param object $object
     */
    public function __construct(object $object)
    {
        $this->object = $object;
    }

    /**
     * @return object
     */
    public function getObject(): object
    {
        return $this->object;
    }
}
Enter fullscreen mode Exit fullscreen mode

Create listener

<?php

namespace App\Listener;

use App\Entity\User;
use App\Event\PreCreateEvent;

/**
 * Class SecurityListener
 * @package App\Listener
 */
class UserListener
{
    /**
     * @param PreCreateEvent $event
     */
    public function __invoke(PreCreateEvent $event): void
    {
        $object = $event->getObject();

        if ($object instanceof User) {
            // do something
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

How to use ?

$listenerProvider = (new ListenerProvider())
        ->addListener(PreCreateEvent::class, new UserListener());

$dispatcher = new EventDispatcher($listenerProvider);

// After flush user in database send event

$dispatcher = new EventDispatcher($listenerProvider);
$dispatcher->dispatch(new PreCreateEvent($user));
Enter fullscreen mode Exit fullscreen mode

UserListener::class will be automatically call

Ideal for small project
Simple and easy!
https://github.com/devcoder-xyz/php-event-dispatcher

💖 💪 🙅 🚩
fadymr
F.R Michel

Posted on January 10, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related