tobento/app-event

应用事件支持。

1.0.2 2024-02-20 18:01 UTC

This package is auto-updated.

Last update: 2024-09-20 19:14:45 UTC


README

使用 事件服务 的应用事件支持。

目录

入门

使用以下命令添加运行中的应用事件项目的最新版本。

composer require tobento/app-event

要求

  • PHP 8.0 或更高版本

文档

应用

如果您使用的是骨架,请查看 应用骨架

您还可以查看 应用 了解有关应用的更多信息。

事件启动

事件启动执行以下操作

  • 安装并加载事件配置文件
  • 实现事件接口
  • 从配置文件添加事件监听器
use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Event\Boot\Event::class);

// Run the app
$app->run();

事件配置

事件的配置位于默认应用骨架配置位置的 app/config/event.php 文件中。

可用事件接口

启动后以下接口可用

use Tobento\App\AppFactory;
use Tobento\Service\Event\ListenersInterface;
use Tobento\Service\Event\EventsFactoryInterface;
use Tobento\Service\Event\EventsInterface;
use Psr\EventDispatcher\EventDispatcherInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Event\Boot\Event::class);
$app->booting();

$listeners = $app->get(ListenersInterface::class);
// is declared as prototype, meaning returning always a new instance!

$eventsFactory = $app->get(EventsFactoryInterface::class);
$events = $app->get(EventsInterface::class);
$eventDispatcher = $app->get(EventDispatcherInterface::class);

// var_dump($events === $eventDispatcher);
// bool(true)

// Run the app
$app->run();

查看 事件服务 了解有关接口的更多信息。

默认事件

您可以通过使用应用内的 Tobento\Service\Event\EventsInterface::class 或通过自动装配来访问默认事件。

此外,事件用作默认 Psr\EventDispatcher\EventDispatcherInterface::class 实现。

创建事件

namespace App\Event;

use App\Entity\User;

final class UserRegistered
{
    public function __construct(
        public readonly User $user
    ) {}
}

创建监听器

namespace App\Listener;

class SendWelcomeMail
{
    public function __invoke(UserRegistered $event): void
    {
        // send welcome mail.
    }
}

查看 定义监听器 部分以了解更多信息。

添加监听器

您可以通过以下方式添加监听器

使用事件配置

您可以在 app/config/event.php 文件中定义监听器

use Tobento\App\Event\ListenerRegistry;
use App\Event;
use App\Listener;

return [

    /*
    |--------------------------------------------------------------------------
    | Default Event Listeners
    |--------------------------------------------------------------------------
    |
    | Define the event listeners for the default events.
    |
    | As the events class uses reflection to scan listeners for its events named $event,
    | there is no need to define its event(s) for a listener.
    | But you might do so if you have multiple events in your listener and
    | want only to listen for the specific events or just because of better overview.
    |
    */
    
    'listeners' => [
        // Specify events to listeners:
        Event\UserRegistered::class => [
            Listener\SendWelcomeMail::class,
            
            // with build-in parameters:
            [Listener::class, ['number' => 5]],
            
            // with specific priority:
            new ListenerRegistry(
                listener: Listener::class,
                priority: 1,
            ),
        ],
        
        // Specify listeners without event:
        'auto' => [
            Listener\SendWelcomeMail::class,
            
            // with build-in parameters:
            [Listener::class, ['number' => 5]],
            
            // with specific priority:
            new ListenerRegistry(
                listener: Listener::class,
                priority: 1,
            ),
        ],
    ],
    
    // ...
];

手动使用事件

您可以通过使用 EventsInterface::class 手动添加监听器。

use Tobento\App\AppFactory;
use Tobento\Service\Event\EventsInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Event\Boot\Event::class);
$app->booting();

$events = $app->get(EventsInterface::class);

// Add listeners
$events->listen(FooListener::class);

$events->listen(AnyListener::class)
       ->event(FooEvent::class)
       ->priority(2000);

// Run the app
$app->run();

查看 添加监听器 了解更多关于添加监听器的信息。

分发事件

您可以通过以下方式分发事件

使用事件调度器

EventDispatcherInterface::class 使用默认事件作为调度器实现。

namespace App\Service;

use Psr\EventDispatcher\EventDispatcherInterface;
use App\Event\UserRegistered;
use App\Entity\User;

final class UserService
{
    public function __construct(
        private readonly EventDispatcherInterface $dispatcher
    ) {}

    public function register(User $user): void
    {
        // ...
        
        $this->dispatcher->dispatch(new UserRegistered($user));
    }
}

使用事件

namespace App\Service;

use Tobento\Service\Event\EventsInterface;
use App\Event\UserRegistered;
use App\Entity\User;

final class UserService
{
    public function __construct(
        private readonly EventsInterface $dispatcher
    ) {}

    public function register(User $user): void
    {
        // ...
        
        $this->dispatcher->dispatch(new UserRegistered($user));
    }
}

特定事件

您可以为特定的服务、组件或包创建特定的事件。

创建事件

要创建特定事件,只需扩展 Events::class

use Tobento\Service\Event\Events;

final class ShopEvents extends Events
{
    //
}

使用应用时,ShopEvents::class 将自动装配。

添加特定监听器

您可以通过以下方式为您的特定事件添加监听器

使用事件配置

您可以在 app/config/event.php 文件中定义监听器

use Tobento\App\Event\ListenerRegistry;

return [
    // ...
    
    /*
    |--------------------------------------------------------------------------
    | Specific Events Listeners
    |--------------------------------------------------------------------------
    |
    | Define the event listeners for the specific events.
    |
    | As the events class uses reflection to scan listeners for its events named $event,
    | there is no need to define its event(s) for a listener.
    | But you might do so if you have multiple events in your listener and
    | want only to listen for the specific events or just because of better overview.
    |
    */
    
    'events' => [
        ShopEvents::class => [
            // Specify events to listeners:
            SomeEvent::class => [
                Listener::class,

                // with build-in parameters:
                [Listener::class, ['number' => 5]],
            ],

            // Specify listeners without event:
            'auto' => [
                Listener::class,

                // with build-in parameters:
                [Listener::class, ['number' => 5]],

                // to define specific priority:
                new ListenerRegistry(
                    listener: Listener::class,
                    priority: 1,
                ),
            ],
        ],
    ],
    
    // ...
];

手动使用事件

您可以通过使用 ShopEvents::class 手动添加监听器。

use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Event\Boot\Event::class);
$app->booting();

$events = $app->get(ShopEvents::class);

// Add listeners
$events->listen(FooListener::class);

$events->listen(AnyListener::class)
       ->event(FooEvent::class)
       ->priority(2000);

// Run the app
$app->run();

查看 添加监听器 了解更多关于添加监听器的信息。

使用应用 on 方法

您可以通过使用应用 on 方法添加监听器。

use Tobento\App\AppFactory;
use Tobento\App\Event\ConfigEventsRegistry;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Event\Boot\Event::class);
$app->booting();

$app->on(ShopEvents::class, function(ShopEvents $shopEvents) {
    // Add listeners
    $shopEvents->listen(FooListener::class);

    // Or add listeners from config:
    (new ConfigEventsRegistry(priority: 1000))->addListenersFromArray(
        events: $shopEvents,
        
        // using same definition as config listeners.
        eventListeners: [
            SomeEvent::class => [
                Listener::class,

                // with build-in parameters:
                [Listener::class, ['number' => 5]],
                
                // ...
            ],
        ],
    );
});
        
// Run the app
$app->run();

查看 添加监听器 了解更多关于添加监听器的信息。

使用事件

在设置完您的特定事件后,您可以在服务中使用它。

namespace App\Service;

use Psr\EventDispatcher\EventDispatcherInterface;

final class ShopService
{
    public function __construct(
        private readonly EventDispatcherInterface $dispatcher
    ) {}
}

// or:
final class AnotherShopService
{
    public function __construct(
        private readonly ShopEvents $dispatcher
    ) {}
}

有几种方法可以将事件注入到您的 ShopService::class

// using a closure:
$app->set(ShopService::class, function() {
    return new ShopService(
        dispatcher: $app->get(ShopEvents::class),
    );
});

// using the construct method:
$app->set(ShopService::class)->construct($app->get(ShopEvents::class));

// using the on method:
$app->on(ShopService::class, ['dispatcher' => ShopEvents::class]);

AnotherShopService::class 无需注入操作,因为 ShopEvents::class 被定义为调度器,它将自动装配。

您可以查看应用定义应用开启方法以获取更多信息。

队列监听器

进行中...

致谢