jasny/event-dispatcher

PSR-14 兼容且易于使用的的事件调度器

v1.0.1 2019-06-03 17:41 UTC

This package is auto-updated.

Last update: 2024-08-29 21:02:14 UTC


README

Build Status Scrutinizer Code Quality Code Coverage Packagist Stable Version Packagist License

一个兼容 PSR-14 且易于使用的事件调度器。

事件调度是一种常见且经过良好测试的机制,允许开发者轻松且一致地将逻辑注入到应用程序中。

PSR 仅要求根据类名确定事件,其他任何方法都是可选的。库应仅依赖于规范,而不是实现,因此每个事件类型都必须有自己的类。

安装

composer require jasny/event-dispatcher

使用

1. 定义您自己的事件类

namespace App\Event;

/**
 * Base class for all events in this application.
 */
abstract class Base
{
    /** @var object */
    protected $emitter;

    /** @var mixed */
    protected $payload;

    public function __construct(object $emitter, $payload = null)
    {
        $this->emitter = $emitter;
        $this->payload = $payload;
    }
    
    final public function getEmitter(): object
    {
        return $this->emitter;
    }

    public function setPayload($payload): void
    {
        $this->payload = $payload;
    }

    public function getPayload()
    {
        return $this->payload;
    }
}

/**
 * Called before an entity is saved to the database.
 */
class BeforeSave extends Base
{}

/**
 * Called when an entity is casted to json.
 */
class ToJson extends Base
{} 

2. 创建监听器

use App\Event;
use Jasny\EventDispatcher\EventDispatcher;
use Jasny\EventDispatcher\ListenerProvider;

$listener = (new ListenerProvider)
    ->withListener(function(Event\BeforeSave $event): void {
        $entity = $event->getEmitter();
        $payload = $event->getPayload();
        
        $payload['bio'] = $payload['bio'] ?? ($entity->name . " just arrived");
        $event->setPayload($payload);
    })
    ->withListener(function(Event\ToJson $event): void {
        $payload = $event->getPayload();
        
        unset($payload['password']);
        $event->setPayload($payload);
    });

提供者将使用监听器第一个参数的类型提示来确定监听器是否适用于给定的事件。

监听器将按注册到提供者的顺序执行。无法预置现有监听器。

3. 创建调度器

$dispatcher = new EventDispatcher($listener);

4. 分发事件

通常主题将保留自己的调度器并触发事件。

use App\Event;
use Jasny\EventDispatcher\EventDispatcher;

class Foo implements JsonSerializable
{
    /**
     * @var EventDispatcher
     */
    protected $eventDispatcher;

    // ...
    
    public function jsonSerialize()
    {
        $payload = get_object_vars($this);
    
        return $this->eventDispatcher->dispatch(new Event\ToJson($this, $payload));
    }
}

添加监听器

ListenerProviderEventDispatcher 是不可变服务。方法 withListenerwithListenerProvider 分别会创建每个服务的修改后的副本。

use App\Event;

$newListener = $dispatcher->getListener()
    ->off(function(Event\BeforeSave $event): void {
        $payload = $event->getPayload();
       
        $payload['bio'] = strtr($payload['bio'], $payload['email'], '***@***.***');
        $event->setPayload($payload);
    });

$newDispatcher = $dispatcher->withListenerProvider($newListener);

可停止的事件

事件必须实现 PSR-14 的 StoppableEventInterface

namespace App\Event;

use Psr\EventDispatcher\StoppableEventInterface;

/**
 * Called before an entity is saved to the database.
 */
class BeforeSave implememnts StoppableEventInterface
{
    // ...

    public function stopPropagation(): void
    {
        $this->propagationStopped = true;
    }

    public function isPropagationStopped(): bool
    {
        return $this->propagationStopped;
    }
}
use App\Event;
use Jasny\EventDispatcher\EventDispatcher;
use Jasny\EventDispatcher\ListenerProvider;

$listener = (new ListenerProvider)
    ->on(function(Event\BeforeSave $event): void {
        $entity = $event->getEmitter();
        
        if (!$entity->isReady()) {
            $event->stopPropagation();
        }
    });
    
$dispatcher = new EventDispatcher($listener);

监听器命名空间

监听器可以注册到提供者的命名空间下。

use App\Event;
use Jasny\EventDispatcher\EventDispatcher;
use Jasny\EventDispatcher\ListenerProvider;

$listener = (new ListenerProvider)
    ->withListenerInNs('censor', function(Event\BeforeSave $event): void {
        $payload = $event->getPayload();
        
        $payload['bio'] = strtr($payload['bio'], $payload['email'], '***@***.***');
        $event->setPayload($payload);
    });
    ->withListenerInNs('censor.json', function(Event $event): void {
        $payload = $event->getPayload();
        
        unset($payload['password']);
        $event->setPayload($payload);
    });

这可以用来删除命名空间及其所有子命名空间内的所有监听器。

$newListeners = $dispatcher->getListenerProvider()->withoutNs('censor');

此示例删除了 censorcensor.json 命名空间中的监听器。

命名空间通配符

您可以使用通配符指定所有子命名空间,无论父命名空间是什么。

$newListeners = $dispatcher->getListenerProvider()->withoutNs('*.json');

此示例删除了 censor.json 命名空间中的监听器。