gpslab / domain-event-bundle
用于创建DDD应用领域层的包
v2.3.1
2021-05-24 12:09 UTC
Requires
- php: >=5.5.0
- doctrine/orm: ~2.4
- gpslab/domain-event: ~2.0
- symfony/dependency-injection: ~2.3|~3.0|~4.0|~5.0
- symfony/expression-language: ~2.3|~3.0|~4.0|~5.0
- symfony/http-kernel: ~2.3|~3.0|~4.0|~5.0
Requires (Dev)
- phpunit/phpunit: ^4.8.36
README
领域事件包
用于创建您的领域驱动设计(DDD)应用的领域层。
此Symfony包是gpslab/domain-event的包装器,更多详情请查看。
安装
使用Composer非常简单,运行
composer req gpslab/domain-event-bundle
配置
示例配置
gpslab_domain_event: # Event bus service # Support 'listener_located', 'queue' or a custom service # As a default used 'listener_located' bus: 'listener_located' # Event queue service # Support 'pull_memory', 'subscribe_executing' or a custom service # As a default used 'pull_memory' queue: 'pull_memory' # Event listener locator # Support 'symfony', 'container', 'direct_binding' or custom service # As a default used 'symfony' locator: 'symfony' # Publish domain events post a Doctrine flush event # As a default used 'false' publish_on_flush: true
使用方法
创建领域事件
use GpsLab\Domain\Event\Event class PurchaseOrderCreatedEvent implements Event { private $customer_id; private $create_at; public function __construct(CustomerId $customer_id, \DateTimeImmutable $create_at) { $this->customer_id = $customer_id; $this->create_at = $create_at; } public function customerId(): CustomerId { return $this->customer_id; } public function createAt(): \DateTimeImmutable { return $this->create_at; } }
抛出事件
use GpsLab\Domain\Event\Aggregator\AbstractAggregateEvents; final class PurchaseOrder extends AbstractAggregateEvents { private $customer_id; private $create_at; public function __construct(CustomerId $customer_id) { $this->customer_id = $customer_id; $this->create_at = new \DateTimeImmutable(); $this->raise(new PurchaseOrderCreatedEvent($customer_id, $this->create_at)); } }
创建监听器
use GpsLab\Domain\Event\Event; class SendEmailOnPurchaseOrderCreated { private $mailer; public function __construct(\Swift_Mailer $mailer) { $this->mailer = $mailer; } public function onPurchaseOrderCreated(PurchaseOrderCreatedEvent $event): void { $message = $this->mailer ->createMessage() ->setTo('recipient@example.com') ->setBody(sprintf( 'Purchase order created at %s for customer #%s', $event->createAt()->format('Y-m-d'), $event->customerId() )); $this->mailer->send($message); } }
注册事件监听器
services: SendEmailOnPurchaseOrderCreated: arguments: [ '@mailer' ] tags: - { name: domain_event.listener, event: PurchaseOrderCreatedEvent, method: onPurchaseOrderCreated }
在监听器中发布事件
use GpsLab\Domain\Event\Bus\EventBus; // get event bus from DI container $bus = $this->get(EventBus::class); // do what you need to do on your Domain $purchase_order = new PurchaseOrder(new CustomerId(1)); // this will clear the list of event in your AggregateEvents so an Event is trigger only once $events = $purchase_order->pullEvents(); // You can have more than one event at a time. foreach($events as $event) { $bus->publish($event); } // You can use one method //$bus->pullAndPublish($purchase_order);
监听器方法名称
您不需要指定事件处理器方法的名称。默认情况下,使用__invoke方法。
use GpsLab\Domain\Event\Event; class SendEmailOnPurchaseOrderCreated { private $mailer; public function __construct(\Swift_Mailer $mailer) { $this->mailer = $mailer; } public function __invoke(PurchaseOrderCreatedEvent $event): void { $message = $this->mailer ->createMessage() ->setTo('recipient@example.com') ->setBody(sprintf( 'Purchase order created at %s for customer #%s', $event->createAt()->format('Y-m-d'), $event->customerId() )); $this->mailer->send($message); } }
注册事件监听器
services: SendEmailOnPurchaseOrderCreated: arguments: [ '@mailer' ] tags: - { name: domain_event.listener, event: PurchaseOrderCreatedEvent }
事件订阅者
创建订阅者
use GpsLab\Domain\Event\Event; use GpsLab\Domain\Event\Listener\Subscriber; class SendEmailOnPurchaseOrderCreated implements Subscriber { private $mailer; public function __construct(\Swift_Mailer $mailer) { $this->mailer = $mailer; } public static function subscribedEvents(): array { return [ PurchaseOrderCreatedEvent::class => ['onPurchaseOrderCreated'], ]; } public function onPurchaseOrderCreated(PurchaseOrderCreatedEvent $event): void { $message = $this->mailer ->createMessage() ->setTo('recipient@example.com') ->setBody(sprintf( 'Purchase order created at %s for customer #%s', $event->createAt()->format('Y-m-d'), $event->customerId() )); $this->mailer->send($message); } }
注册事件订阅者
services: SendEmailOnPurchaseOrderCreated: arguments: [ '@mailer' ] tags: - { name: domain_event.subscriber }
使用Predis队列
composer require predis/predis
注册服务
services: # Predis Predis\Client: arguments: [ '127.0.0.1' ] # Events serializer for queue GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer: arguments: [ '@serializer', 'json' ] # Predis event queue GpsLab\Domain\Event\Queue\Pull\PredisPullEventQueue: arguments: - '@Predis\Client' - '@GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer' - '@logger' - 'event_queue_name'
更改配置以使用自定义队列
gpslab_domain_event: queue: 'GpsLab\Domain\Event\Queue\Pull\PredisPullEventQueue'
现在您可以使用自定义队列
use GpsLab\Domain\Event\Queue\EventQueue; $container->get(EventQueue::class)->publish($domain_event);
从队列中拉取事件
use GpsLab\Domain\Event\Queue\EventQueue; $queue = $container->get(EventQueue::class); $bus = $container->get(EventQueue::class); while ($event = $queue->pull()) { $bus->publish($event); }
使用Predis订阅队列
使用Composer安装Predis PubSub适配器,运行
composer require superbalist/php-pubsub-redis
注册服务
services: # Predis Predis\Client: arguments: [ '127.0.0.1' ] # Predis PubSub adapter Superbalist\PubSub\Redis\RedisPubSubAdapter: arguments: [ '@Predis\Client' ] # Events serializer for queue GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer: arguments: [ '@serializer', 'json' ] # Predis event queue GpsLab\Domain\Event\Queue\Subscribe\PredisSubscribeEventQueue: arguments: - '@Superbalist\PubSub\Redis\RedisPubSubAdapter' - '@GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer' - '@logger' - 'event_queue_name'
更改配置以使用自定义队列
gpslab_domain_event: queue: 'GpsLab\Domain\Event\Queue\Subscribe\PredisSubscribeEventQueue'
现在您可以使用自定义队列
use GpsLab\Domain\Event\Queue\EventQueue; $container->get(EventQueue::class)->publish($domain_event);
在队列上订阅
use GpsLab\Domain\Event\Queue\EventQueue; $container->get(EventQueue::class)->subscribe(function (Event $event) { // do somthing });
注意
您可以使用订阅处理器作为服务,并通过标签优化注册。
多个队列
您可以使用多个队列来分离流程。例如,您可能想将不同边界上下文的事件分别处理。
services: acme.domain.purchase_order.event.queue: class: GpsLab\Domain\Event\Queue\Pull\PredisPullEventQueue arguments: - '@Superbalist\PubSub\Redis\RedisPubSubAdapter' - '@GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer' - '@logger' - 'purchase_order_event_queue' acme.domain.article_comment.event.queue: class: GpsLab\Domain\Event\Queue\Pull\PredisPullEventQueue arguments: - '@Superbalist\PubSub\Redis\RedisPubSubAdapter' - '@GpsLab\Domain\Event\Queue\Serializer\SymfonySerializer' - '@logger' - 'article_comment_event_queue'
现在您可以使用不同的队列。
在采购订单边界上下文中。
$event = new PurchaseOrderCreatedEvent( new CustomerId(1), new \DateTimeImmutable() ); $container->get('acme.domain.purchase_order.event.queue')->publish($event);
在文章评论边界上下文中。
$event = new ArticleCommentedEvent( new ArticleId(1), new AuthorId(1), $comment new \DateTimeImmutable() ); $container->get('acme.domain.article_comment.event.queue')->publish($event);
注意
类似地,您可以将订阅队列分割。
许可证
此包受MIT许可证的约束。请参阅文件中的完整许可证:LICENSE