event-engine/php-engine
CQRS/Event Sourcing framework for PHP to rapidly build event-sourced applications and evolve toward richer domain models. Customize architecture and programming style via “Flavours,” with a full tutorial and separate documentation repo.
Full Changelog: https://github.com/event-engine/php-engine/compare/v0.17.0...v0.17.1
#27 bumped php-persistence to v0.8, due to changes in php-document-store
JsonSchemaAwareRecordcreatedAt property to AggregateEventEnvelopeloadAggregateEvents that derives stream name from aggregate description. It also turns each GenericEvent into an AggregateEventEnvelope for easy access to event metadata and the custom event instance, if configured Flavour returns one. See tests for details.nullThe Bugfix #15 and the new Feature #16 can cause a BC Break if you use a ContextProvider that returns null or has a void return type. Prior to this release a null context was ignored by Event Engine. If you inject one or more services in the same aggregate function, the services would directly be injected after the command. This is fixed now. Hence, the aggregate function receives a null after the command followed by services.
We consider this change a bugfix, because null is a valid context and should not be ignored by Event Engine.
Let's use an example to make it clear:
$eventEngine->process(Command::DO_SOMETHING)
->withNew(Aggregate::SOMETHING)
->provideContext(NullContextProvider::class)
->provideService(SomeService::class)
// Using a closure as aggregate function for easier understanding
// SomeService is directly injected after the command
->handle(function (Message $doSomething, SomeService $someService) {
})
$eventEngine->process(Command::DO_SOMETHING)
->withNew(Aggregate::SOMETHING)
->provideContext(NullContextProvider::class)
->provideService(SomeService::class)
// Null is injected (result of the context provider call) followed by the service
->handle(function (Message $doSomething, $nullableContext, SomeService $someService) {
})
EventEngine::enableMetadataForwarding() during set up phase of the Event Engine to enable the new feature. Once enabled you can pass an array of metadata to EventEngine::dispatch() and Event Engine will add the metadata to all messages caused by the dispatch call. This includes recorded events, follow up commands, events caused by follow up commands, etc. Even when dispatching custom messages you can pass metadata as an array: $eventEngine->dispatch($myCustomCmd, [], ['metadata' => 'goes here']); Please note: when using prooph v7 event-store your metadata array should only contain keys with scalar values!In Event Machine and in Event Engine prior to this release it was only possible to inject a context object into aggregate functions using a context provider. Event Engine emphasise the usage of a functional core, which basically means: avoid side effects in aggregate functions. However, using dependencies in aggregate functions that fetch data from a database or remote service is not always a bad idea. Maybe fetching data is only needed if the aggregate has a certain state or you simply want to express data fetching as part of the business logic and record an event if it fails. Whatever reason you have, injecting one or more services into aggregate functions is now as easy as using a context provider:
private static function describeConnectWithFriend(EventEngine $eventEngine): void
{
$eventEngine->process(Command::CONNECT_WITH_FRIEND)
->withExisting(Aggregate::USER)
->provideService(GetUserResolver::class) // <-- Service id should be known by DI Container
->provideService(MessageFactory::class) // <-- order of provideService() calls determines order of handle function arguments
->handle(function (UserState $user, Message $connectWithFriend, GetUserResolver $resolver, MessageFactory $messageFactory): \Generator
{
$friendId = $connectWithFriend->get(CacheableUserDescription::FRIEND);
//Check that friend exists using a resolver dependency
$friend = $resolver->resolve($messageFactory->createMessageFromArray(Query::GET_USER, [
'payload' => [CacheableUserDescription::IDENTIFIER => $friendId]
]));
yield [Event::FRIEND_CONNECTED, [
CacheableUserDescription::IDENTIFIER => $user->userId,
CacheableUserDescription::FRIEND => $friend[CacheableUserDescription::IDENTIFIER],
]];
})
->recordThat(Event::FRIEND_CONNECTED)
->apply(function (UserState $user, Message $friendConnected): UserState
{
$user->friends[] = $friendConnected->get(CacheableUserDescription::FRIEND);
return $user;
});
}
See the full example (and more) here: https://github.com/event-engine/php-engine/blob/master/examples/PrototypingFlavour/Aggregate/UserDescription.php
It's also possible to combine a context provider and services. In that case the context object is injected first, followed by the services. This behavior ensures, that existing aggregate functions with contexts continue to work.
As stated above: existing aggregate functions that use a context object continue to work. But to support the new feature a small change in the Flavour interface was needed: https://github.com/event-engine/php-engine/commit/98ad903c7afe38ee8a19a3ee5179e5b9117c12f5#diff-00eabf99719cb7185f5cb7f2de7d52e4
If you use a custom Flavour or the OopFlavour and therefor your own OopPort, you have to adjust it. See changes in the examples: https://github.com/event-engine/php-engine/commit/98ad903c7afe38ee8a19a3ee5179e5b9117c12f5#diff-dd975e16429f155208da76975871669b
EventEngine::env() and EventEngine::debugMode() methodsFixed: Parse error in ProjectionInfo
Support document store named indices
Minor BC Break: DocumentStore interface has 3 new methods to check,add and drop named indices on collections
This release marks the second milestone towards a stable Event Engine release. All namespaces previously defined in the php-engine mono-repo are now moved to their own packages.
Please find a complete list of all new packages here
Event Engine supersedes Event Machine
It will become a new major version taking all the great ideas of Event Machine and add many new features on top.
The namespace change is required due to naming conflicts with existing projects. We were able to register event-engine.io which will become the new home for the online documentation and some more stuff.
Version 0.1 marks an important milestone. All concepts of Event Machine have been ported to Event Engine and we've added many new features. We don't expect bigger breaking changes from now on. Event Engine is already used in a project, so we were able to test and verify the new features in the real world and not only in pet projects!
One of the goals for a new major release was to remove usage of prooph/event-sourcing and prooph/service-bus. Read more about it here
This work is completed. Event Engine takes over message routing as it holds the config for it anyway. The event sourcing mechanism is now based on a custom implementation, specifically designed to support the ideas behind Event Engine.
We tried to support the public API of Event Machine in Event Engine as much as possible. However, some changes are not compatible with Event Engine and require a migration. If you need a migration guide please ping us! Event Machine had no stable release (v1.0 of Event Machine is released at the same time as v0.1 of Event Engine). We plan to provide a list of changes and of course a list of all new features. However, a detailed migration instruction is not planed due to missing time!
We're heading towards Event Engine v1.0, but there is still a lot of work ahead.
To ease initial development of new features and the new Event Engine core, we've put all code in the event-engine/php-engine repo. If you look at it you'll recognize that it uses multiple namespaces. Each namespace will be moved to its own repository on github, except the Event Engine core. That said, while it's enough to require event-engine/php-engine: v0.1 today, you'll need to require more packages in the future. A skeleton application similar to the current Event Machine Skeleton will provide a default set of packages for fast project ramp up.
Once the repo is split, we'll release a v0.2 of all packages and start to add tests to each. At the moment main functionality of Event Engine is tested with high level integration tests, but don't expect a fully stable system. We make heavy use of EE in a project, but we don't use all new features yet and also use a custom Flavour for the project because we've migrated an existing code base from prooph v6 to EE.
Documentation of Event Machine was never completed. The tutorial covered everything to get started and we definitely plan to provide a similar one for Event Engine. However, this time an incomplete documentation is considered as a blocker for a stable v1.0 release. While still being very beginner friendly, Event Engine is grown into a very flexible framework suitable for all kinds of projects. This requires comprehensive documentation so that everybody can use the full power of Event Engine.
How can I help you explore Laravel packages today?