Prooph Event Store

Prooph Event Store is the central component of this package. If you are familiar with doctrine you can compare it with doctrine's EntityManager. However, Prooph Event Store is especially designed to add a centralized, event-driven system on top of different low level event stream persistence adapters (f.e. MySQL or Postgres). The event-driven store is the unique selling point of prooph/event-store compared to other libraries. So let's directly jump into it and see what you can do with it.

ReadOnlyEventStoreWrapper

In case you need a read only event store, you can wrap your existing event store implementation with the ReadOnlyEventStoreWrapper.

$readOnlyEventStore = new ReadOnlyEventStoreWrapper($eventStore);

Event Hooks

Requirements: an event store wrapped with Prooph\EventStore\ActionEventEmitterEventStore.

Action events are triggered when methods of the event store are invoked. The action events are named like the event store methods. The following events are available (event target is always the event store):

  • create: event params: stream - result params: streamExistsAlready
  • appendTo: event params: streamName, streamEvents - result params: streamNotFound, concurrencyException
  • load: event params: streamName, fromNumber, count, metadatamatcher - result params: streamEvents, streamNotFound
  • loadReverse: event params: streamName, fromNumber, count, metadatamatcher - result params: streamEvents, streamNotFound
  • delete: event params: streamName - result params: streamNotFound
  • hasStream: event params: streamName - result params: result
  • fetchStreamMetadata: event params: streamName - result params: metadata, streamNotFound
  • updateStreamMetadata: event params: streamName, metadata - result params: streamNotFound
  • fetchStreamNames: event params: filter, metadataMatcher, limit, offset - result params: streamNames
  • fetchStreamNamesRegex: event params: filter, metadataMatcher, limit, offset - result params: streamNames
  • fetchCategoryNames: event params: filter, offset, limit - result params: categoryNames
  • fetchCategoryNamesRegex: event params: filter, offset, limit - result params: categoryNames

If the event store implements \Prooph\EventStore\TransactionalActionEventEmitterEventStore, the following additional events are available:

  • beginTransaction: event params: none - result params: transactionAlreadyStarted
  • commit: event params: none - result params: transactionNotStarted
  • rollback: event params: none - result params: `transactionNotStarted

Attaching Plugins

If you took a look at the quick start, you should already be familiar with the possibility to attach an event listener plugin.

$eventStore->attach(
    'commit',
    function (\Prooph\Common\Event\ActionEvent $actionEvent) {
        //plugin logic here
    },
    1000 // priority
);

More complex plugins are typically provided as classes with their own dependencies. A plugin can implement the Prooph\EventStore\Plugin\Plugin interface and can then attach itself to the event store in the Plugin::attachToEventStore($eventStore) method. Implementing the interface is especially useful when you use the event store factory.

Plugin Use Cases

The event-driven system opens the door for customizations. Here are some ideas of what you can do with it:

  • Attach a domain event dispatcher on the create and appendTo event
  • Filter events before they are stored
  • Add event metadata like a causation id (id of the command which caused the event)
  • Convert events into custom event objects before they are passed back to a repository
  • Implement your own Unit of Work and synchronize it with the transaction, commit and rollback events
  • ...

Metadata enricher

By default, the component is shipped with a plugin to automatically add metadata to each event. For instance, you may want to add information about the command which caused the event or even the user who triggered that command.

Here is an example of its usage:

<?php

use Prooph\Common\Messaging\Message;
use Prooph\EventStore\Metadata\MetadataEnricher;
use Prooph\EventStore\Metadata\MetadataEnricherAggregate;
use Prooph\EventStore\Metadata\MetadataEnricherPlugin;

class IssuerMetadataEnricher implements MetadataEnricher
{
    // ...

    public function enrich(Message $event): Message
    {
        if ($this->currentUser) {
            $event = $event
                ->withAddedMetadata('issuer_type', 'user')
                ->withAddedMetadata('issuer_id', $this->currentUser->id());
        }

        return $event;
    }
}

$plugin = new MetadataEnricherPlugin(new MetadataEnricherAggregate([
  $issuerMetadataEnricher,
  $causationMetadataEnricher,
  $otherMetadataEnricher,
]));

$plugin->attachToEventStore($eventStore);

Internal metadata

All internal metadata is prefixed with _ (underscore), f.e. _causation_id. Do not use metadata keys starting with an underscore, as this is reserved for prooph internals.

Fork me on GitHub