Skip to content

Latest commit

 

History

History
284 lines (220 loc) · 10.4 KB

event_store.md

File metadata and controls

284 lines (220 loc) · 10.4 KB

Event Store

This documentation covers just the configuration of Prooph Event Stores in Symfony. To inform yourself about the Prooph Event Store, please have a look at its official documentation.

Setting up a MySQL PDO Event Store

To setup a MySQL PDO Event Store we need the prooph/pdo-event-store package.

composer require prooph/pdo-event-store

Hint: You can also follow this instruction if you want to setup a PDO Event Store for MariaDB or PostgreSQL. You just need to use other classes which are also part of the prooph/pdo-event-store package. For further details please have a look at the prooph/pdo-event-store package.

Before we setup our event store, we need to setup some services:

# app/config/services.yml or (flex) config/packages/prooph_event_store.yaml
services:
    prooph_event_store.pdo_mysql_event_store:
        class: Prooph\EventStore\Pdo\MySqlEventStore
        arguments:
            - '@prooph_event_store.message_factory'
            - '@pdo.connection'
            - '@prooph_event_store.mysql.single_stream_strategy'
            
    prooph_event_store.mysql.single_stream_strategy:
        class: Prooph\EventStore\Pdo\PersistenceStrategy\MySqlSingleStreamStrategy
        
    pdo.connection:
        class: PDO
        arguments: ['%dsn%']

Hint: For reusing a PDO connection from Doctrine please see below.

Hint: You can also use other stream strategies. Have a look at the documentation of the prooph/pdo-event-store package to learn about the different strategies. See below for further information within this bundle.

Do not be confused about the fact that the we defined a service with a class called event store – we are not done yet. But we are ready to configure the event store:

# app/config/config.yml or (flex) config/packages/prooph_event_store.yaml
prooph_event_store:
    stores:
        acme_store:
            event_store: 'prooph_event_store.pdo_mysql_event_store'

Hint: To get autocompletion in some IDEs you can prepend the service id with an @ ('@prooph_event_store.pdo_mysql_event_store').

The bundle will recognize this and find your event store anyway.

We configured our first event store. To put data into the event store (and read them from it) we might want to add repositories.

Adding repositories to the event store

If you are adding repositories to your event_store, you want to go for event sourcing. Therefore we will explain how to add an event sourced repository.

First you need to install another package, prooph/event-sourcing](http://docs.getprooph.org/event-sourcing/):

composer require prooph/event-sourcing

Before we can start adding our repositories, we need to define another service:

# app/config/config.yml or (flex) config/packages/prooph_event_store.yaml
services:
    prooph_event_sourcing.aggregate_translator:
        class: Prooph\EventSourcing\EventStoreIntegration\AggregateTranslator

It will help our repository to translate the event stream into an aggregate and vice versa.

We assume that there is

  • a class Acme\Prooph\Repository\EventStoreUserRepository which extends Prooph\EventSourcing\Aggregate\AggregateRepository
  • and a class Acme\Model\User which extends Prooph\EventSourcing\AggregateRoot.

More information about Aggregate Roots and Aggregate Repositories can be found in the official documentation.

Now we can configure our repository:

# app/config/config.yml or (flex) config/packages/prooph_event_store.yaml
prooph_event_store:
    stores:
        acme_store:
            event_store: 'prooph_event_store.pdo_mysql_event_store'
            repositories:
                Acme\Prooph\Repository\EventStoreUserRepository:
                    aggregate_type: Acme\Model\User
                    aggregate_translator: 'prooph_event_sourcing.aggregate_translator'

Hint: To get autocompletion in some IDEs you can prepend the service id with an @ ('@prooph_event_sourcing.aggregate_translator').

The bundle will recognize this and find your event store anyway.

Now you can access the repository from the service container with the id Acme\Prooph\Repository\EventStoreUserRepository.

Hint: If you do not want your repositories to have their classes as service ids, you can configure them like this:

# app/config/config.yml or (flex) config/packages/prooph_event_store.yaml
prooph_event_store:
    stores:
        acme_store:
            event_store: 'prooph_event_store.pdo_mysql_event_store'
            repositories:
                acme.repository.prooph.event_store_user_repository:
                    repository_class: Acme\Prooph\Repository\EventStoreUserRepository
                    aggregate_type: Acme\Model\User
                    aggregate_translator: 'prooph_event_sourcing.aggregate_translator'

This way your repository will be accessible with the service id acme.repository.prooph.event_store_user_repository.

Reusing a PDO connection from Doctrine

If you already have a PDO connection configured through doctrine and you want to use the same connection for your event store, there is a simple way to reuse it:

# app/config/services.yaml
services:
    prooph_event_store.connection.doctrine_pdo_connection:
        class: PDO
        factory: ['@doctrine.dbal.default_connection', getWrappedConnection]

Using different Stream Strategies

To make yourself familiar with different stream strategies, please have a look at the documentation of the prooph/pdo-event-store package.

If you want to use one of the Single Stream Strategies, you just need to set up the Strategy as a service and pass it to the event store:

# app/config/services.yml or (flex) config/packages/prooph_event_store.yaml
services:
    prooph_event_store.pdo_mysql_event_store:
        class: Prooph\EventStore\Pdo\MySqlEventStore
        arguments:
            - '@prooph_event_store.message_factory'
            - '@pdo.connection'
            - '@prooph_event_store.mysql.single_stream_strategy'
            
    prooph_event_store.mysql.single_stream_strategy:
        class: Prooph\EventStore\Pdo\PersistenceStrategy\MySqlSingleStreamStrategy
        
    pdo.connection:
        class: PDO
        arguments: ['%dsn%']

If you want to use one of the Aggregate Stream Strategies, you also need to configure your Stream Strategie as a service like above. But you also need to your repositories to follow this strategy using the one_stream_per_aggregate option:

# app/config/config.yml or (flex) config/packages/prooph_event_store.yaml
prooph_event_store:
    stores:
        acme_store:
            event_store: 'prooph_event_store.pdo_mysql_event_store'
            repositories:
                Acme\Prooph\Repository\EventStoreUserRepository:
                    aggregate_type: Acme\Model\User
                    aggregate_translator: 'prooph_event_sourcing.aggregate_translator'
                    one_stream_per_aggregate: true

Because this option defaults to false, this is only necessary for Aggregate Stream Strategies.

Plugins

A prooph Event Store can be expanded using plugins. If you want to know more about Event Store Plugins, please have a look at the official documentation.

Adding plugins to an Event Store is really simple. Let's assume that we already have a class implementing Prooph\EventStore\Plugin\Plugin and that we have configured it as service:

# app/config/services.yml
services:
    acme.prooph.plugins.example_plugin:
        class: Acme\Prooph\Plugins\ExamplePlugin

To attaching the plugin to an Event Store, we just need to tag it with prooph_event_store.<STORE-NAME>.plugin. So if our Event Store is named acme_store, it would look like this:

# app/config/services.yml
services:
    acme.prooph.plugins.example_plugin:
        class: Acme\Prooph\Plugins\ExamplePlugin
        tags:
            - { name: 'prooph_event_store.acme_store.plugin' }

If you cant to attach to plugin to multiple Event Stores, just tag it multiple times. In the special case that you want to attach the plugin to every Event Store, you can use the tag prooph_event_store.plugin instead.

Metadata enricher

If you do not know what a metadata enricher is, please have a look at the official documentation of Metadata enricher.

Let's assume that we want to add the issuer of an event to the metadata. Our Metadata enricher might look like this:

<?php

declare(strict_types=1);

namespace Acme\Prooph\MetadataEnricher;

use Prooph\Common\Messaging\Message;
use Prooph\EventStore\Metadata\MetadataEnricher;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class IssuerMetadataEnricher implements MetadataEnricher
{
    /** @var TokenStorageInterface */
    private $tokens;
    
    public function __construct(TokenStorageInterface $tokens)
    {
        $this->tokens = $tokens;
    }
    
    public function enrich(Message $message): Message
    {
        if ($this->tokens->getToken()) {
            $message = $message
                ->withAddedMetadata('issuer_type', 'user')
                ->withAddedMetadata('issuer_name', $this->tokens->getToken()->getUsername());
        }
        return $message;
    }
}

And our service definition like this:

# app/config/services.yml
services:
    acme.prooph.metadata_enricher.issuer:
        class: Acme\Prooph\MetadataEnricher\IssuerMetadataEnricher
        arguments: ['@security.token_storage']

To enable the enricher for every Event Store, we just need to tag the service:

# app/config/services.yml
services:
    acme.prooph.metadata_enricher.issuer:
        class: Acme\Prooph\MetadataEnricher\IssuerMetadataEnricher
        arguments: ['@security.token_storage']
        tags:
            - { name: 'prooph_event_store.metadata_enricher' }

But be careful, this tag would add the metadata enricher to every Event Store. If you want to add it only to one store, you need to use the tag prooph_event_store.<STORE-NAME>.metadata_enricher.