Comments (4)
The CommandDispatchResult contains some information about the dispatch, for example the effected aggregate id and the recorded events (if any).
In one project we return the aggregate id back to the client, because it is generated on-the-fly for new aggregates and the client needs to know it.
Recorded events could be inspected or pushed to a message queue.
If a command preprocessor returns a CommandDispatchResult, dispatching is stopped (see https://github.com/event-engine/php-engine/blob/master/src/EventEngine.php#L804). You can use this to stop command handling. This is especially useful if you have a preprocessor that acts as an async switch: The preprocessor can check command metadata. If it contains for example an handled_async
key the prprocessor does nothing and command dispatching goes on.
If the key is not present, the preprocessor pushes the command on an async queue and aborts the current dispatch. This way your commands (or some of them, depends on your implementation) can be handled async while still using a single Event Engine configuration.
Also CommandDispatchResult is used for logging.
Unfortunately, docs are not complete here, but I hope my short answers gives you some idea what you can do with it.
from php-engine.
Ok, Thx for the information!
I've looked into the source code and was wondering what could be the meaning of the CommandDispatchResult.
And now I know that I misuse the CommandDispatchResult to return an Id.
I know this is not the way CQRS works, but in our case we had to find a way to return data from the controllers, so I used a CommandDispatchResult filled with a MessageBag to return an Id.
Our backend systems would need a big refactor to send uuid's from the client, that's the reason why we retrieve a generated id from the backend.
If you got some better solutions/tweaks for this particular case, be my guest
But I also realize, that you can't implement something like this in the library, otherwise you would break the main rule of CQRS
Thx!
from php-engine.
It's ok, we do the same! You just need to be aware that you cannot handle commands async in that case or you have to generate the id on the server, pass it to the command bevor it is pushed on a queue and return that id back to the client.
Here is how we do it in a current project:
Modified MessageboxHandler
public function handle(ServerRequestInterface $request): ResponseInterface
{
$payload = null;
$messageName = 'UNKNOWN';
$metadata = [];
try {
$payload = $request->getParsedBody();
$messageName = $request->getAttribute('message_name', $messageName);
if (\is_array($payload) && isset($payload['message_name'])) {
$messageName = $payload['message_name'];
$metadata = $payload['metadata'] ?? [];
$payload = $payload['payload'] ?? [];
}
$result = $this->messageDispatcher->dispatch($messageName, $payload, $metadata);
if ($result === null) {
return new EmptyResponse(StatusCodeInterface::STATUS_ACCEPTED);
}
// Here we use the CommandDispatchResult to get a newly created aggrgateId
// In fact, all command responses include the effected aggregate id
if ($result instanceof CommandDispatchResult) {
if ($effectedAggregateId = $result->effectedAggregateId()) {
return new JsonResponse(
['aggregateId' => $effectedAggregateId],
StatusCodeInterface::STATUS_ACCEPTED
);
}
return new EmptyResponse(StatusCodeInterface::STATUS_ACCEPTED);
}
if (is_object($result) && method_exists($result, 'toArray')) {
$result = $result->toArray();
}
return new JsonResponse($result);
} catch (\InvalidArgumentException $e) {
throw new \RuntimeException(
$e->getMessage(),
StatusCodeInterface::STATUS_BAD_REQUEST,
$e
);
}
}
And here is an example command that is handled by a new aggregate and therefor generates the aggregate id if not present in the command payload:
<?php
declare(strict_types=1);
namespace Acme\Configuration\Domain\Model\Customer\Command;
use EventEngine\Data\ImmutableRecord;
use EventEngine\Data\ImmutableRecordLogic;
use EventEngine\JsonSchema\JsonSchema;
use EventEngine\Schema\PayloadSchema;
use Acme\Application\Domain\Model\Base\AggregateCommand;
use Acme\Application\Domain\Model\Base\ProvidesPayloadSchema;
use Acme\Application\Domain\Model\InternationalAddress;
use Acme\Configuration\Domain\Api\Payload;
use Acme\Configuration\Domain\Api\Schema;
use Acme\Configuration\Domain\Model\Customer\CustomerId;
use Acme\Configuration\Domain\Model\Customer\CustomsId;
use Acme\Configuration\Domain\Model\Customer\Name;
use Acme\Configuration\Domain\Model\Customer\TaxId;
class AddCustomer implements ImmutableRecord, AggregateCommand, ProvidesPayloadSchema
{
use ImmutableRecordLogic;
/** @var CustomerId */
private $customerId;
/** @var Name */
private $name;
/**
* @var InternationalAddress
*/
private $businessAddress;
/**
* @var CustomsId
*/
private $customsId;
/**
* @var TaxId
*/
private $taxId;
private function init(): void
{
if (null === $this->customerId) {
$this->customerId = CustomerId::generate();
}
}
public function name() : Name
{
return $this->name;
}
public function customerId() : CustomerId
{
return $this->customerId;
}
public function aggregateId(): string
{
return $this->customerId->toString();
}
public function businessAddress() : InternationalAddress
{
return $this->businessAddress;
}
public function customsId() : CustomsId
{
return $this->customsId;
}
public function taxId() : TaxId
{
return $this->taxId;
}
public static function payloadSchema(): PayloadSchema
{
return JsonSchema::object(
[
Payload::NAME => Schema::name(),
Payload::CUSTOMS_ID => Schema::customsId(),
Payload::TAX_ID => Schema::taxId(),
Payload::BUSINESS_ADDRESS => Schema::internationalAddress(),
],
[
Payload::CUSTOMER_ID => Schema::customerId(),
]
);
}
}
All our messages are ImmutableRecord
s and use immutable value objects. They also provide their own payload schema which is passed to the Event Engine registerMessageType method.
As you can see, CustomerId
is marked as an optional property in the schema and in the ImmutableRecord::init
function we check if it is null and generate a new one in that case. The newly generated customer id is added automatically to the CommandDispatchResult by Event Engine.
from php-engine.
Thx for the info, glad to see, we almost implemented it the same way :-)
from php-engine.
Related Issues (14)
- Check uniqueness of Command, Query and Event names HOT 3
- EventEngine::rebuildAggregateState does not work as expected with MultiModelStore HOT 1
- Using the specification pattern in combination with Event Engine HOT 4
- Describe differences between original project and fork HOT 1
- How does migration work? HOT 2
- Next Gen Event Engine
- Context Providers should also receive the state if exists HOT 2
- Support dedicated dispatcher for commands
- Method fromCachedConfig should only load config
- Any roadmap? HOT 3
- Cannot rewind a generator that was already run HOT 3
- Process manager in event-engine HOT 2
- Restore aggregate root in event engine HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from php-engine.