cvek / domain-events
添加领域事件功能的组件
3.0.0
2022-05-12 12:01 UTC
Requires
- php: ^7.4|^8.0
- doctrine/orm: ^2.0
- symfony/config: ^4.0|^5.0|^6.0
- symfony/dependency-injection: ^4.0|^5.0|^6.0
- symfony/doctrine-bridge: ^4.0|^5.0|^6.0
- symfony/event-dispatcher: ^4.0|^5.0|^6.0
- symfony/http-kernel: ^4.0|^5.0|^6.0
- symfony/messenger: ^4.0|^5.0|^6.0
Requires (Dev)
- roave/security-advisories: dev-master
README
此包集成了Symfony应用程序以提供领域事件支持。这允许在业务逻辑实现期间无Doctrine依赖地触发事件。
领域事件分为三种类型
preFlush。在持久化到数据库之前将同步处理;onFlush。在持久化到数据库期间(同步或异步 - 见下文)处理;postFlush。在持久化到数据库之后(同步或异步 - 见下文)处理。
要使用此包,请在您的实体类中实现 RaiseEventsInterface 接口并创建自定义领域事件。我们建议您使用 RaiseEventsTrait 来简化此过程。
同步/异步消息
任何领域事件都可以在 onFlush 和 postFlush Doctrine事件期间以 sync 或 async 方式执行。通过扩展以下抽象类之一: AbstractSyncDomainEvent 或 AbstractAsyncDomainEvent 来获得相应的 sync 或 async 事件。
异步方式是一种非常强大的方法,必须在以下情况下使用
多亏了 db 传输与doctrine存储(将自动创建) - 所有异步领域事件都将自动路由并持久化到数据库。
为了消费它们,我们建议使用以下supervisor配置
[program:db]
command=/srv/api/bin/console messenger:consume db --memory-limit=128M --time-limit=3600 --limit=100
process_name=%(program_name)s_%(process_num)02d
numprocs=1
autostart=true
autorestart=true
startsecs=0
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
⚠️ 不要忘记将其添加到您的应用程序中!
直接异步消息
如果您不想编写自己的异步消息处理程序,但直接派发消息,则只需在您的消息中扩展 AbstractDirectAsyncDomainEvent 并以此方式使用它即可
use Doctrine\ORM\Events; public function setName(string $name): self { $this->name = $name; $this->raise(new NameChangedDirectAsyncMessage($this)); return $this; }
消息将被直接派发到总线,而无需编写自己的处理程序。
示例
安装
composer req cvek/domain-events
使用
创建领域事件
同步事件
use \Cvek\DomainEventsBundle\EventDispatch\Event\AbstractSyncDomainEvent; final class FooNameChanged extends AbstractSyncDomainEvent { private Foo $foo; private string $oldName; private string $newName; public function __construct(Foo $foo, string $oldName, string $newName) { $this->foo = $foo; $this->oldName = $oldName; $this->newName = $newName; } public function getFoo(): Foo { return $this->foo; } public function getOldName(): string { return $this->oldName; } public function getNewName(): string { return $this->newName; } public function isAsync() : bool { return false; } }
异步事件
use \Cvek\DomainEventsBundle\EventDispatch\Event\AbstractAsyncDomainEvent; final class FooPasswordChanged extends AbstractAsyncDomainEvent { private Foo $foo; private string $password; public function __construct(Foo $foo, string $password) { $this->foo = $foo; $this->password = $password; } public function getFoo(): Foo { return $this->foo; } public function getPassword(): string { return $this->password; } public function isAsync() : bool { return true; } }
在业务层中触发事件
use \Cvek\DomainEventsBundle\Entity\RaiseEventsInterface; use \Cvek\DomainEventsBundle\Entity\RaiseEventsTrait; class Foo implements RaiseEventsInterface { use RaiseEventsTrait; private string $name; public function setName(string $name): self { $this->raise(new FooNameChanged($this, $this->name, $name)); $this->name = $name; return $this; } public function setPassword(string $password): self { $this->raise(new FooPasswordChanged($this, $password)); return $this; } }
在监听器中捕获事件
当调用 flush 操作时,所有在您的实体中引发的事件将被收集并派发。您可以通过常规方式监听它们。
监听同步消息
use \Symfony\Component\EventDispatcher\EventSubscriberInterface; use \Doctrine\ORM\Events; final class FooNameListener implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ FooNameChanged::class => 'onNameChange' ]; } public function onNameChange(FooNameChanged $event): void { if ($event->getLifecycleEvent() === Events::preFlush) { // your custom logic on preFlush moment: logging, validation etc... } if ($event->getLifecycleEvent() === Events::onFlush) { // your custom logic on onFlush moment } if ($event->getLifecycleEvent() === Events::postFlush) { // your custom logic on postFlush moment } } }
监听异步消息
use \Doctrine\ORM\Events; use \Symfony\Component\Messenger\Handler\MessageHandlerInterface; final class FooPasswordHandler implements MessageHandlerInterface { public function __invoke(FooPasswordChanged $event) { if ($event->getLifecycleEvent() === Events::preFlush) { // your custom logic on preFlush moment: logging, validation etc... } if ($event->getLifecycleEvent() === Events::onFlush) { // your custom logic on onFlush moment } if ($event->getLifecycleEvent() === Events::postFlush) { // your custom logic on postFlush moment } } }