Download the PHP package neos/event-sourcing without Composer

On this page you can find all versions of the php package neos/event-sourcing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package event-sourcing

Event Sourcing and CQRS for Flow Framework and Symfony

Library providing interfaces and implementations for event-sourced applications.

Getting started

Install this package via composer:

Setting up an Event Store

Since there could be multiple Event Stores simultaneously in one application, this package no longer comes with a pre-configured "default" store. It is just a matter of a couple of lines of YAML to configure a custom store:

Configuration/Settings.yaml:

This registers an Event Store, identified as "Some.Package:EventStore"1, that uses the provided Doctrine storage adapter that persists events in a database table2.

To make use of the newly configured Event Store one more step is required in order to finish the setup (in this case to create the corresponding database table):

:information_source:  Note... > By default, the Event Store persists events in the same database that is used for Flow persistence. > But because that can be configured otherwise, this table is not generated via Doctrine migrations. > If your application relies on the events table to exist, you can of course still add a Doctrine migration for it.

Obtaining the Event Store

To get hold of an instance of a specific Event Store the EventStoreFactory can be used:

:information_source:  Alternative ways... Alternatively you can inject the Event Store directly: But in this case you have to specify _which_ event store to be injected. This can be done easily using Flow's [Object Framework](https://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/ObjectManagement.html#object-framework): *Configuration/Objects.yaml:* If you use Flow 6.2 or newer, you can make use of the [virtual object configuration](https://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/ObjectManagement.html#virtual-objects) to simplify the process: *Configuration/Objects.yaml:* And, finally, if you happen to use the event store from many classes, you could of course create a custom Event Store facade like: *Classes/CustomEventStore.php* and inject that.

Writing events

Example event: SomethingHasHappened.php

Reading events

Reacting to events with Event Listeners / Projectors

A Projector is a special Event Listener which does not have side-effects (besides updating the projection), and can thus be reset and replayed.

In order to react upon new events you'll need an Event Listener:

The when*() methods of classes implementing the EventListenerInterface will be invoked whenever a corresponding event is committed to the Event Store.

Since it is possible to have multiple Event Stores the listener has to be registered with the corresponding Store:

Configuration/Settings.yaml:

This registers the Some\Package\SomeEventListener so that it is updated whenever a corresponding event was committed to the "Some.Package:EventStore".

To register all/multiple listeners with an Event Store, you can use regular expressions, too:

Configuration/Settings.yaml:

Keep in mind though that a listener can only ever by registered with a single Event Store (otherwise you'll get an exception at "compile time").

In case you implement a projector, you should implement ProjectorInterface.

Triggering Side-Effects after Projections have been updated

Sometimes, it is necessary to refresh dependent data after a certain projection has been updated.

WARNING: If possible, first try hard to build a second, independent projection. Refreshing state after a projection has updated is something like a "dependent projection" which only makes sense if the same data of the projection is stored in another representation (e.g. a data warehouse, or a search index).

This can be implemented in two ways:

Variant 1: implement AfterInvokeInterface in your Projector, and directly trigger an external action.

The afterInvoke method is triggered for every event, thus there is no batching or anything like that. This is fine in simpler scenarios, but not if you have loads of events which always lead to similar refresh actions.

Variant 2: implement AfterCatchUpInterface

The afterCatchUp method is triggered at the end of a projector update run, and can be used to fire off a batch update to an external system.

In case you want to implement chunking (i.e. trigger an update of the external system every e.g. 100 events), you can do that by implementing both AfterInvokeInterface and AfterCatchUpInterface: In afterInvoke, you would see if the chunk size was reached (and if yes, trigger the external call and reset your tracking state). In afterCatchUp you would trigger the remaining calls for the unfinished batch at the end.

Reacting to Events Synchronously (i.e. Projection Update Synchronously)

When embracing asynchronicity, you establish a scaling point where the application can be "torn apart":

On the other hand, asynchronicity introduces complexity, that will leak to many other application parts. Usually, the frontend then needs to implement optimistic updates and failure handling.

WARNING: You will give up one of the main performance advantages of Event Sourcing. Think twice before doing this, and think through your assumptions of the system, because we all have a tendency to prefer the "simple, synchronous world".

For smaller amounts of moving data, where you won't run into performance problems due to synchronous execution, it is sometimes useful to move back to a "synchronous" mode, where the projections are DIRECTLY updated after the events are stored.

How can we force a projection (or another event listener) to run synchronously?

You can call the Neos\EventSourcing\EventListener\EventListenerInvoker::catchup() method directly - this then calls the projectors (and other event listeners as needed).

Best is if you create a service which contains the following snippet for each projector you want to update synchronously:

Event Sourced Aggregate

The neos/event-sourcing package comes with a base class that can be used to implement Event-Sourced Aggregates.

Aggregate Construction

The AbstractEventSourcedAggregateRoot class has a private constructor. To create a fresh aggregate instance you should define a named constructor:

Aggregate Repository

This Framework does not provide an abstract Repository class for Aggregates, because an implementation is just a couple of lines of code and there is no useful abstraction that can be extracted. The Repository is just a slim wrapper around the EventStore and the Aggregate class:

Tutorial

See Tutorial.md

Glossary

See Glossary.md


1: The Event Store identifier is arbitrary, but it's good practice prefixing it with a package key in order to prevent naming clashes ↩ 2: The Doctrine Event storage uses the same database connection that is configured for Flow and persists events in a table neos_eventsourcing_eventstore_events by default – this can be adjusted, see ↩


All versions of event-sourcing with dependencies

PHP Build Version
Package Version
Requires php Version >=8.0
neos/flow Version ^7.0 || ^8.0 || ^9.0 || dev-master
flowpack/jobqueue-common Version ^3.0 || dev-master
symfony/serializer Version ^5.1
symfony/property-access Version ^5.1
ramsey/uuid Version ^3.9 || ^4.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package neos/event-sourcing contains the following files

Loading the files please wait ....