Ecotoneprovide us with possibility to handle cross cutting concerns via
Interceptoras name suggest, intercepts the process of handling the message. You may enrich the message, stop or modify usual processing cycle, call some shared functionality, add additional behavior to existing code without modifying the code itself.
Administrators should be able to change the cost of a product
product.changePricebut we want to avoid code duplication, especially logic that may happen more often. Let's intercept our
RequireAdministratorin new namepace
Before Interceptor.Start by removing old
UserServiceand create new one in different namespace
App\Infrastructure\RequireAdministrator. Remember to mark return type as
void, we will see why it is so important soon.
Before- marks method as
Interceptor, so it can be be found by
Pointcut- describes what should be intercepted.
CLASS_NAME- indicates what should be intercepted using specific
Attribute Nameannotated at the level of method or class
expression||expression- Indicating one expression or another e.g.
Before Interceptorthat it should intercept all endpoints with annotation
RequireAdministrator.Now, whenever we will call our command handlers, they will be intercepted by
UserService. You can try it out, by providing different
Afterinterceptors are depending on the return type, to decide if they should modify Message or pass it through. If return type is different than void, Message payload or headers can be enriched with data. If return type is void then message will be passed through and the process of message flow can be interrupted by throwing exception only.
Ecotoneif this Interceptor modifies
headers. The default is
headersare picked and associative array must be returned. The returned value is merged with current headers. If
payloadis picked and current payload is replaced by returned value, the headers stays the same. You may of course inject current payload and headers into the method if needed, as with usual endpoint.
Ecotonein what order interceptors should be called. The lower the value is the quicker interceptor will be called. The order exists within interceptor type:
before/around/after.We want to call
RequireAdministrator Interceptoras it require
userIdto exists, in order to verify.
AddUserIdServicehas precedence of
0as default, so
UserServicemust have at least
Aroundyou decide to break the flow, return
Nullindiciates, that there is no message and the current flow ends. Null can not be returned in header changing interceptor, it does work only for payload changing interceptor.
Around Interceptoris closet to actual endpoint's method call. Thanks to that, it has access to
Method Invocation.This does allow for starting some procedure and ending after the invocation is done.
sqlitedatabase. Before we do that, we need to remove our In Memory implementation class
App\Domain\Product\InMemoryProductRepositorywe will replace it with our new implementation. We will create using new namespace for it
App\Infrastructure\Persistence.Besides we are going to use doctrine/dbal, as this is really helpful abstraction over the PDO.
Connectionto sqlite database using dbal library
Serializeris Gateway registered by
Ecotone.Serializer can handle serialization using Converters. It this case it will know how to register
Costclass, as we already registered Converter for it. Serializer give us access for conversion
from PHPtype to specific Media Type or from specific Media Type
to PHPtype. We will use it to easily serialize our
JSONand store it in database.
idof the aggregate, the
classtype and serialized
JSON. Take a look at
createSharedTableIfNeededif you want more details.
Command Bus Gatewaywith transaction. So whenever we call it, it will invoke our Command Handler within transaction.
Command Bus.In case of Command Bus it may seems not needed, but if we would intercept Aggregate, then it really useful as for example you may verify if executing user have access to it. You may read more about interceptors in dedicated section.