spiral-packages/event-bus

基于 symfony 事件处理器的简单观察者模式实现,允许您订阅并监听应用程序内发生的各种事件。

2.2.0 2022-07-20 10:11 UTC

This package is auto-updated.

Last update: 2024-09-07 06:14:17 UTC


README

PHP Latest Version on Packagist GitHub Tests Action Status Total Downloads

订阅并监听应用程序内发生的各种事件。

需求

请确保您的服务器配置了以下 PHP 版本和扩展

  • PHP 8.0+
  • Spiral 框架 2.9+

安装

您可以通过 composer 安装此包

composer require spiral-packages/event-bus

安装包后,您需要从包中注册引导加载器。

protected const LOAD = [
    // ...
    \Spiral\EventBus\Bootloader\EventBusBootloader::class,
];

namespace App\Bootloader;

use Spiral\EventBus\Bootloader\EventBusBootloader as BaseBootloader

class EventBusBootloader extends BaseBootloader
{
    protected const LISTENS = [
        \App\Event\UserCreated::class => [
            \App\Listener\SendWelcomeMessageListener::class
        ],
        //...
    ];
}

使用

首先需要创建配置文件 app/config/event-bus.php,其中您可以指定监听器。

<?php

declare(strict_types=1);

return [
    'queueConnection' => env('EVENT_BUS_QUEUE_CONNECTION'), // default queue connection for Listeners with \Spiral\EventBus\QueueableInterface
    'discoverListeners' => env('EVENT_BUS_DISCOVER_LISTENERS', true), // Discover listeners with \Spiral\EventBus\Attribute\Listener attribute
    'listeners' => [
        UserDeleted::class => [
            DeleteUserComments::class,
        ]
    ],
    'interceptors' => [
        BroadcastEventInterceptor::class
    ]
];

您还可以通过 Spiral\EventBus\ListenerRegistryInterface 注册监听器

class MyPackageBootloader extends Spiral\Boot\Bootloader\Bootloader
{
    public function start(Spiral\EventBus\ListenerRegistryInterface $registry) 
    {
        $registry->addListener(UserDeleted::class, DeleteUserComments::class);
    }
}

事件示例

class UserDeleted 
{
    public function __construct(public string $name) {}
}

监听器示例

确保在事件处理方法中使用变量 $event。这是必需的。

class DeleteUserComments 
{
    public function __construct(private CommentService $service) {}
    
    public function __invoke(UserDeleted $event)
    {
        $this->service->deleteCommentsForUser($event->name);
    }
}

带有属性的监听器示例

如果您使用带有属性 'discoverListeners' = true 的监听器,则无需注册它们,它们将自动注册。

use Spiral\EventBus\Attribute\Listener;

class DeleteUserComments 
{
    public function __construct(private CommentService $service) {}
    
    #[Listener]
    public function handleDeletedUser(UserDeleted $event)
    {
        $this->service->deleteCommentsForUser($event->usernname);
    }
    
    #[Listener]
    public function handleCreatedUser(UserCreated $event)
    {
        $this->service->creaateUserProfile($event->usernname);
    }
    
    #[Listener]
    public function notifyAdmins(UserCreated|UserDeleted $event)
    {
        $this->service->notifyAdmins($event->usernname);
    }
}

需要在队列中处理的监听器示例

如果您想将监听器推送到队列中,可以添加 Spiral\EventBus\QueueableInterface

class DeleteUserComments implements \Spiral\EventBus\QueueableInterface
{
    // ...
}

事件分发

use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class UserService 
{
    public function __construct(private EventDispatcherInterface $events) {}
    
    public function deleteUserById(string $id): void
    {
        $user = User::findById($id);
        //.. 
        
        $this->events->dispatch(
            new UserDeleted($user->username)
        );
    }
}

拦截器

该包提供方便的 Bootloader 以自动配置核心拦截器 Spiral\EventBus\Bootloader\EventBusBootloader

namespace App\Bootloader;

use Spiral\EventBus\Bootloader\EventBusBootloader as BaseBootloader

class EventBusBootloader extends BaseBootloader
{
    protected const INTERCEPTORS = [
        \App\Event\Interceptor\BroadcastEventInterceptor::class,
        //...
    ];
}

或通过配置 app/config/event-bus.php

<?php

declare(strict_types=1);

return [
    // ...
    'interceptors' => [
        BroadcastEventInterceptor::class
    ]
];
namespace App\Event\Interceptor;

use Spiral\Broadcasting\BroadcastInterface;

class BroadcastEventInterceptor implements \Spiral\Core\CoreInterceptorInterface
{
    public function __construct(
        private BroadcastInterface $broadcast
    ) {}
    
    public function process(string $eventName, string $action, array , CoreInterface $core): mixed
    {
        $event = $parameters['event']; // Event object
        $listeners = $parameters['listeners']; // array of invokable listeners
        
        $result = $core->callAction($eventName, $action, $parameters);     
        
        if ($event instanceof ShouldBroadcastInterface) {
            $this->broadcast->publish(
                $event->getBroadcasTopics(), 
                \json_encode($event->toBroadcast())
            );
        }
        
        return $result;
    }
}

测试

composer test

如果您在应用程序中使用 spiral/testing 包,您还可以在测试用例中使用 trait Spiral\EventBus\Testing\InteractsWithEvents

class EventDispatcherTest extends TestCase
{
    use \Spiral\EventBus\Testing\InteractsWithEvents;

    public function testDispatchEvent(): void
    {
        $events = $this->fakeEventDispatcher();
    
        $this->getDispatcher()->dispatch(new SimpleEvent());
    
        $events->assertListening(SimpleEvent::class, SimpleListener::class);
        $events->assertListening(SimpleEvent::class, ListenerWithAttributes::class, 'methodA');
        
        $events->assertDispatched(SimpleEvent::class)
        
        $events->assertDispatched(SimpleEvent::class, function(SimpleEvent $event) {
            return $event->someProperty === 'foo';
        });

        $events->assertDispatchedTimes(SimpleEvent::class, 10);
        
        $events->assertNotDispatched(AnotherSimpleEvent::class);
        
        $events->assertNotDispatched(AnotherSimpleEvent::class);
        
        $events->assertNothingDispatched();
    }
}

变更日志

请参阅 CHANGELOG 了解最近更改的信息。

贡献

请参阅 CONTRIBUTING 了解详细信息。

安全漏洞

请查看我们的安全策略 以了解如何报告安全漏洞

致谢

许可证

MIT 许可证 (MIT)。请参阅 许可证文件 了解更多信息。