承接 star/domain-event 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

star/domain-event

Composer 安装命令:

composer require star/domain-event

包简介

Domain events extension

README 文档

README

Build Status

Small implementation of the aggregate root in ddd. The AggregateRoot implementation triggers events that can be collected for publishing by an implementation of EventPublisher.

Installation

  • Add the package using composer in your composer.json

composer require star/domain-event

Usage

  1. Make your class inherit the AggregateRoot class.
// Product.php
class Product extends AggregateRoot
{
}
  1. Create the event for the mutation.
class ProductWasCreated implements DomainEvent
{
    private string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function name(): string
    {
        return $this->name;
    }
}
  1. Create a named constructor (static method), and a mutation method. The protected method will be invoked internally using the naming standard of mutation methods.
// 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()));
    }
  1. Create the callback method on the AggregateRoot that would be used to set the state after an event mutation.
    protected function onProductWasCreated(ProductWasCreated $event): void
    {
        $this->name = $event->name();
    }
}

Listening to an event

When you wish to perform an operation after an event was dispatched by the EventPublisher, you need to define your listener:

class DoSomethingProductCreated implements EventListener
{
    // methods on listener can be anything, it is configured by getListenedEvents
    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 static function getListenedEvents(): 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',
            ],
        ];
    }
}

The listener needs to be given to the publisher, so that he can send the event.

$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->publish(...$product->uncommitedEvents()); // will notify the listener and call the DoSomethingProductCreated::doSomething() method

Warning: Be advised that events will be removed from aggregate once collected and published, to avoid republishing the same event twice.

We currently support third party adapters to allow you to plug-in the library into your infrastructure.

Naming standard

The events method on the AggregateRoot children must be prefixed with on and followed by the event name. ie. For an event class named StuffWasDone the aggregate should have a method:

protected function onStuffWasDone(StuffWasDone $event): void;

Note: The callback method can be changed to another format, by overriding the AggregateRoot::getEventMethod().

protected function getEventMethod(DomainEvent $event): string
{
    if ($event instanceof StuffWasDone) {
        return 'whenYouDoStuff'; // the protected method whenYouDoStuff() would be invoked to apply the change to the aggregate
    }
}

Message bus

The package adds the ability to dispatch messages (Command and Query). Compared to the EventPubliser, the CommandBus and QueryBus have different usages.

  • Command bus: Responsible to dispatch an operation that returns nothing.
  • Query bus: Responsible to fetch some information. The returned information is recommended to be returned in a readonly format.

(Example of usage)

Serialization of events

When persisting your event in a data store, you may use a PayloadSerializer instance to convert your event to a serializable string. The current implementation PayloadFromReflection allow you to:

Example

The blog example shows a use case for a blog application.

Symfony usage

Using a Symfony application, you may use the provided compiler passes to use the buses.

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());
}

Once registered, three new tags will be available:

  • star.command_handler
  • star.query_handler
  • star.event_publisher

The tags star.command_handler and star.query_handler have an optional attribute message to specify the message FQCN that will be mapped to this handler. By default the system will try to resolve the same FQCN as the handler, without the Handler suffix.

// 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 }

Note: In both cases, omitting the message attributes would result in the same behavior.

Event store

Event stores are where your events will be persisted. You define which platform is used by extending the provided store.

Example with DBALEventStore.

统计信息

  • 总下载量: 399.98k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 0
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 1
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2016-05-25

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固