star / domain-event
领域事件扩展
2.5.2
2024-01-21 17:59 UTC
Requires
- php: ^7.1|^8.0
- ext-json: *
- beberlei/assert: ^3.3
- webmozart/assert: ^1.1
Requires (Dev)
- doctrine/dbal: ^2.0|^3.0
- phpstan/phpstan: *
- phpstan/phpstan-phpunit: *
- phpunit/php-file-iterator: ^2.0
- phpunit/phpunit: ^7.0|^8.0|^9.0
- squizlabs/php_codesniffer: ^3.4
- symfony/contracts: ^1.0
- symfony/dependency-injection: >=4.3
- symfony/event-dispatcher: >=2.5
Suggests
- symfony/event-dispatcher: Allows the usage of the SymfonyPublisher adapter provided by the star/domain-event.
README
在ddd中实现聚合根的小型示例。AggregateRoot实现会触发事件,可以被EventPublisher的实现收集并发布。
安装
- 使用composer在您的
composer.json
中添加包
composer require star/domain-event
使用
- 让您的类继承AggregateRoot类。
// Product.php class Product extends AggregateRoot { }
- 为变更创建事件。
class ProductWasCreated implements DomainEvent { private $name; public function __construct(string $name) { $this->name = $name; } public function name(): string { return $this->name; } }
- 创建一个命名构造函数(静态方法)或变更方法。
// Product.php /** * Static construct, since the __construct() is protected * * @param string $name * @return Product */ public static function draftProduct(string $name): Product { return self::fromStream([new ProductWasCreated($name)]); } /** * Mutation method that handles the business logic of your aggregate */ public function confirm(): void { $this->mutate(new ProductWasConfirmed($this->getId())); }
- 在AggregateRoot上创建一个回调方法,该方法用于在事件变更后设置状态。
protected function onProductWasCreated(ProductWasCreated $event): void { $this->name = $event->name(); } }
监听事件
当您希望在EventPublisher发布事件后执行操作时,您需要定义您的监听器
class DoSomethingProductCreated implements EventListener { // methods on listener can be anything, it is configured by listensTo public function doSomething(ProductWasCreated $event): void { // do something with the event } public function doSomethingAtFirst(PostWasPublished $event): void { } public function doSomethingInBetween(PostWasPublished $event): void { } public function doSomethingAtLast(PostWasPublished $event): void { } public function listensTo(): array { return [ ProductWasCreated::class => 'doSomething', // priority will be assigned at runtime PostWasPublished::class => [ // multiple methods may be assigned priority 100 => 'doSomethingAtFirst', 0 => 'doSomethingInBetween', -20 => 'doSomethingAtLast', ], ]; } }
监听器需要提供给发布者,以便它可以发送事件。
$publisher = new class() implements EventPublisher {}; // your implementation choice $publisher->subscribe(new DoSomethingProductCreated()); // This is a subscriber that listens to the ProductWasCreated event $product = Product::draftProduct('lightsaber'); $publisher->publishChanges($product->uncommitedEvents()); // will notify the listener and call the DoSomethingProductCreated::doSomething() method
警告:请注意,一旦收集,事件将从聚合中删除,以避免重复发布同一事件。
我们目前支持第三方适配器,允许您将库集成到您的基础设施中。
命名规范
AggregateRoot子类的events方法必须以前缀on开头,后跟事件名。例如,对于名为StuffWasDone的事件类,聚合应该有一个方法
protected function onStuffWasDone(StuffWasDone $event): void;
注意:可以通过覆盖AggregateRoot::getEventMethod()将回调方法更改为其他格式。
消息总线
该包添加了派发消息(命令和查询)的能力。与EventPubliser相比,CommandBus和QueryBus有不同的用法。
- 命令总线:负责派发一个不返回任何内容的操作。
- 查询总线:负责获取一些信息。建议将返回的信息以只读格式返回。
(使用示例)
示例
blog示例展示了博客应用程序的使用场景。
Symfony使用
使用Symfony应用程序,您可以使用提供的编译器传递来使用总线。
use Star\Component\DomainEvent\Ports\Symfony\DependencyInjection\CommandBusPass; use Star\Component\DomainEvent\Ports\Symfony\DependencyInjection\EventPublisherPass; use Star\Component\DomainEvent\Ports\Symfony\DependencyInjection\QueryBusPass; // Kernel.php public function build(ContainerBuilder $container): void { $container->addCompilerPass(new CommandBusPass()); $container->addCompilerPass(new QueryBusPass()); $container->addCompilerPass(new EventPublisherPass()); }
一旦注册,将提供三个新标签
star.command_handler
star.query_handler
star.event_publisher
标签star.command_handler
和star.query_handler
有一个可选属性message
,用于指定映射到该处理器的消息FQCN。默认情况下,系统将尝试解析与处理器相同的FQCN,但无需Handler
后缀。
// services.yaml
services:
Path/For/My/Project/DoStuffHandler:
tags:
- { name star.command_handler, message: Path/For/My/Project/DoStuff }
Path/For/My/Project/FetchStuffHandler:
tags:
- { name star.query_handler, message: Path\For\My\Project\FetchStuff }
注意:在这两种情况下,省略message属性将导致相同的行为。
事件存储
事件存储是您事件持久化的地方。您通过扩展提供的存储来定义使用哪个平台。
示例与DBALEventStore
。