2017 © Pedro Peláez
 

library domain-event

Domain events extension

image

star/domain-event

Domain events extension

  • Sunday, July 2, 2017
  • by yvoyer
  • Repository
  • 1 Watchers
  • 1 Stars
  • 14 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 4 Versions
  • 0 % Grown

The README.md

domain-event

Build Status, (*1)

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

Installation

  • Add the package using composer in your composer.json

composer require star/domain-event, (*3)

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:, (*4)

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., (*5)

$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., (*6)

We currently support third party adapters to allow you to plug-in the library into your infrastructure., (*7)

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:, (*8)

protected function onStuffWasDone(StuffWasDone $event): void;

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

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., (*10)

  • 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), (*11)

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: * register PropertyValueTransformer to ensure your value objects are converted to a serializable format. * Or implement the SerializableAttribute interface to contain the logic in each of your value objects., (*12)

Example

The blog example shows a use case for a blog application., (*13)

Symfony usage

Using a Symfony application, you may use the provided compiler passes to use the buses., (*14)


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:, (*15)

  • 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., (*16)

// 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., (*17)

Event store

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

Example with DBALEventStore., (*19)

The Versions

02/07 2017

dev-master

9999999-dev

Domain events extension

  Sources   Download

MIT

The Requires

  • php >=5.5.0

 

The Development Requires

02/07 2017

1.0.1

1.0.1.0

Domain events extension

  Sources   Download

MIT

The Requires

  • php >=5.5.0

 

The Development Requires

25/05 2016

1.0.0

1.0.0.0

Domain events extension

  Sources   Download

MIT

The Requires

  • php >=5.5.0

 

The Development Requires

24/11 2014

0.1.0

0.1.0.0

Domain events extension

  Sources   Download

MIT

The Requires

 

The Development Requires