Skip to content

0.5.0 Dev Release

Pre-release
Pre-release
Compare
Choose a tag to compare
@codeliner codeliner released this 08 May 21:07
· 56 commits to master since this release

Added

Support service injection into aggregate functions

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.

Minor BC Break

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: 98ad903#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: 98ad903#diff-dd975e16429f155208da76975871669b