tobento / app-event
应用事件支持。
Requires
- php: >=8.0
- psr/event-dispatcher: ^1.0
- tobento/app: ^1.0
- tobento/app-migration: ^1.0
- tobento/service-dir: ^1.0
- tobento/service-event: ^1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- tobento/service-filesystem: ^1.0.5
- vimeo/psalm: ^4.0
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
被定义为调度器,它将自动装配。
队列监听器
进行中...