Plugins & Extensions

A prooph Event Store can be expanded using plugins. Some plugins are provided by prooph but you can write your own ones to customize the event store using event hooks.

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.

ReadOnlyEventStoreWrapper

The event store interface is divided into read-only methods, see Prooph\EventStore\ReadOnlyEventStore and write methods see Prooph\EventStore\EventStore. This distinction is useful in situations where you want to enforce ready-only access to the event store.

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

$readOnlyEventStore = new ReadOnlyEventStoreWrapper($eventStore);
Fork me on GitHub