How to get the created object in controller when implementing CQRS - php

I am evaluating the CQRS pattern and wonder what would be the best way to obtain an Entity created by a command in the same action so I can render it in the view.
The two options I can think of are.
1) Create an id in the controller and send it with the command to fetch the entity by finding it by id.
2) Create an instance of the entity and send it with the command so I have a reference to it after it's populated
Example code
public function createEntityAction(array $data) {
$eventDispatcher = $this->get('event_dispatcher');
$eventDispatcher->dispatch(
CreateEntityHandler::name, // Handler
new Entity($data) // Command
);
// Placeholder //
$entity = get-the-created-entity
// //
return $this->view($entity, Response::HTTP_OK);
}

Second option is not really an option. "Entity creation", which is in fact is a business operation, is a command handling.
Generally speaking, the one who sends a command, whose handler creates an entity, should send the entity id with it. In what way the identity is generated is just an implementation concern.
Usually, command handlers either do what they suppose to do and return nothing (or ACK) or throw (or NAK).

Related

How to retrieve newly created entity by asynchronous command (CQRS) in same php process?

I am implementing PHP application with CQRS.
Let's say I have CreateOrderCommand and when I do
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
CommandBus now just pass command to proper CreateOrderCommandHandler class as easily as:
abstract class SimpleCommandBus implements CommandBus
{
/** #var ICommandHandlerLocator */
protected $locator;
/**
* Executes command
*
* #param Command $command
*/
public function handle(Command $command)
{
$handler = $this->locator->getCommandHandler($command);
$handler->handle($command);
}
}
Everything ok.
But handling is void method, so I do not know anything about progress or result. What can I do to be able to for example fire CreateOrderCommand and then in same process acquire newly created entity id (probably with some passive waiting for its creation)?
public function createNewOrder(/** some data**/){
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
// something that will wait until command is done
$createdOrder = // some magic that retrieves some adress to result data
return $createdOrder;
}
And to get closer of what CQRS can provide, command bus should be able to have RabbitMqCommandBus implementation that just serializes command and sends it to rabbit queue.
So, then the process that finally handles command might be some running consumer and some kind of communication between processes is needed here - to be able to somehow inform original user process from consumer, that it is done (with some information, for example id of new entity).
I know that there is solution with GUID - I could mark command with GUID. But then what:
public function createNewOrder(/** some data**/){
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
$guid = $command->getGuid();
// SOME IMPLEMENTATION
return $createdOrder;
}
SOME IMPLEMENTATION should do some checking of events (so I need to implement some event system too) on command with specific GUID, to be able to for example echo progress or on OrderCreatedEvent just return it's ID that I would get from that event. Consumer process that asynchronously handles command might for example feed events to rabbit and user client would taking them and do proper response (echo progress, return newly created entity for example).
But how to do that? And is solution with GUID the only one? What are acceptable implementations of solutions? Or, what point am I missing? :)
The easiest solution to get information about id of created aggregate/entity is to add it to the command. So the frontend generates the id and pass it with the data. But to make this solution works, you need to make use of uuid instead of normal database integers, otherwise you may find yourself duplicating identifiers on the db side.
If the command is async and perform so time consuming actions, you can for sure publish events from the consumer. So the client via.e.g. websockets receives the informations in real time.
Or ask the backend about existance of the order with the id from the command, from time to time and when the resource exists, redirect him to the right page.

How to get data back from a command bus?

I'm fairly new to domain driven design concepts and I've run into a problem with returning proper responses in an API while using a command bus with commands and command handlers for the domain logic.
Let's say we’re building an application with a domain driven design approach. We have a back end and front end portion. The back end has all of our domain logic with an exposed API. The front end uses the API to make requests to the application.
We're building our domain logic with commands and command handlers mapped to a command bus. Under our Domain directory we have a command for creating a post resource called CreatePostCommand. It's mapped to its handler CreatePostCommandHandler via the command bus.
final class CreatePostCommand
{
private $title;
private $content;
public function __construct(string $title, string $content)
{
$this->title = $title;
$this->content= $content;
}
public function getTitle() : string
{
return $this->title;
}
public function getContent() : string
{
return $this->content;
}
}
final class CreatePostCommandHandler
{
private $postRepository;
public function __construct(PostRepository $postRepository)
{
$this->postRepository = $postRepository;
}
public function handle(Command $command)
{
$post = new Post($command->getTitle(), $command->getContent());
$this->postRepository->save($post);
}
}
In our API we have an endpoint for creating a post. This is routed the createPost method in a PostController under our Application directory.
final class PostController
{
private $commandBus;
public function __construct(CommandBus $commandBus)
{
$this->commandBus = $commandBus;
}
public function createPost($req, $resp)
{
$command = new CreatePostCommand($command->getTitle(), $command->getContent());
$this->commandBus->handle($command);
// How do we get the data of our newly created post to the response here?
return $resp;
}
}
Now in our createPost method we want to return the data of our newly created post in our response object so our front end application can know about the newly created resource. This is troublesome since we know that by definition the command bus should not return any data. So now we're stuck in a confusing position where we don't know how to add our new post to the response object.
I'm not sure how to proceed with this problem from here, several questions come to mind:
Is there an elegant way to return the post's data in the response?
Am I incorrectly implementing the Command/CommandHandler/CommandBus pattern?
Is this simply just the wrong use case for the Command/CommandHandler/CommandBus pattern?
First, notice that if we wire the controller directly to the command handler, we face a similar problem:
public function createPost($req, $resp)
{
$command = new CreatePostCommand($command->getTitle(), $command->getContent());
$this->createPostCommandHandler->handle($command);
// How do we get the data of our newly created post to the response here?
return $resp;
}
The bus is introducing a layer of indirection, allowing you to decouple the controller from the event handler, but the problem you are running into is more fundamental.
I'm not sure how to proceed with this problem from here
TL;DR - tell the domain what identifiers to use, rather than asking the domain what identifier was used.
public function createPost($req, $resp)
{
// TADA
$command = new CreatePostCommand($req->getPostId()
, $command->getTitle(), $command->getContent());
$this->createPostCommandHandler->handle($command);
// happy path: redirect the client to the correct url
$this->redirectTo($resp, $postId)
}
In short, the client, rather than the domain model or the persistence layer, owns the responsibility of generating the id of the new entity. The application component can read the identifier in the command itself, and use that to coordinate the next state transition.
The application, in this implementation, is simply translating the message from the DTO representation to the domain representation.
An alternative implementation uses the command identifier, and derives from that command the identities that will be used
$command = new CreatePostCommand(
$this->createPostId($req->getMessageId())
, $command->getTitle(), $command->getContent());
Named UUIDs are a common choice in the latter case; they are deterministic, and have small collision probabilities.
Now, that answer is something of a cheat -- we've really only demonstrated that we don't need a result from the command handler in this case.
In general, we would prefer to have one; Post/Redirect/Get is a good idiom to use for updating the domain model, but when the client gets the resource, we want to make sure they are getting a version that includes the edits they just made.
If your reads and writes are using the same book of record, this isn't a problem -- whatever you read is always the most recent version available.
However, cqrs is a common architectural pattern in domain driven design, in which case the write model (handling the post) will redirect to the read model -- which is usually publishing stale data. So you may want to include a minimum version in the get request, so that the handler knows to refresh its stale cache.
Is there an elegant way to return the post's data in the response?
There's an example in the code sample you provided with your question:
public function createPost($req, $resp)
Think about it: $req is a representation of the http request message, which is roughly analogous to your command, and $resp is essentially a handle to a data structure that you can write your result into.
In other words, pass a callback or a result handle with your command, and let the command handler fill in the details.
Of course, that depends on your bus supporting callbacks; not guaranteed.
Another possibility, which doesn't require changing the signature of your command handler, is to arrange that the controller subscribes to events published by the command handler. You coordinate a correlation id between the command and the event, and use that to pull up the result event that you need.
The specifics don't matter very much -- the event generated when processing the command could be written to a message bus, or copied into a mailbox, or....
I am using this approach and I am returning command results. However, this is a solution which works only if the command handlers are part of the same process. Basically, I'm using a mediator, the controller and the command handler get an instance of it (usually as a constructor dependency).
Pseudo code controller
var cmd= new MyCommand();
var listener=mediator.GetListener(cmd.Id);
bus.Send(cmd);
//wait until we get a result or timeout
var result=listener.Wait();
return result;
Pseudo code command handler function
var result= new CommandResult();
add some data here
mediator.Add(result,cmd.Id);
That's how you get immediate feedback. However, this shouldn't be used to implement a business process.
Btw, this has nothing to do with DDD, it's basically a message driven CQS approach which can be and it is used in a DDD app.

Doctrine2: How to handle missing relation documents

within a huge dataset I sometimes get inconsistencies when one document is deleted. Symfony2 App with Doctrine ODM and FosREST
$a = new Element();
$b = new Element();
$c = new List();
$c->addElement($a);
$c->addElement($b);
$em->persist($c);
saving at this point works flawlessly
in 99% of the cases $a and $b are still valid Documents when $c is loaded later.
BUT sometimes either $a or $b is deleted without updating the reference in $c.
-> at this moment the next loading of $c will fail with a \Doctrine\ODM\MongoDB\DocumentNotFoundException
(message is something like: The "MongoDBODMProxies__CG__\App\Model\Element" document with identifier "541417702798711d2900607c" could not be found.)
What is the best approach now to handle this case?
I was thinking about either
catching the Exception and to check if the reference it tried to load was on the Element Model
custom exception Handler in fosRest to check for
custom repository function in the mapping and to check there if everything is still valid (+ to store somehow that there is a missing Element) -> but this then forces me to check on every occasion if the "error" is set
UPDATE: The Mapping between the Documents is a bit more complex than I described here
for one the element is basically a collection separated by a discriminator, where only one type of fields references another document (I call it "Tree" now)
a tree can be used in thousands of ElementTree's (that specific type that contains a Tree)
sometimes Tree's can be deleted (this is already a slow running process since a lot of data needs to be updated then)
I would now need to find out what Lists need to change and basically reject the api calls to those lists with the information that a specific element is no longer available.
A few things to check especially for MongoDB:
Make sure that there are no circular references (for example if you have the property $elements on the class List and references set to true on it, make sure List is not referenced on the Elements class as well) and your mappings are consistent.
In the addElement function IF the reference is held on the Element class make sure you also call $element->setList($this) inside the function. (and the same for removeElement, unset the reference if neccessary)
Make sure you cascade all the necessary operations. (For example cascade : ["persist", "delete", "refresh" or "all" ]
You can check your mappings with
$ app/console doctrine:mongodb:mapping:info
Finally if you expect that document to be deleted but you get an error from the proxy object you can clear the metadata cache
$ app/console doctrine:mongodb:cache:clear-metadata
Inperfect Solution that works for now
I now chose to throw a new Exception (it is important not let doctrine throw one because it will reject then any persist attempts in the same request).
In the PostLoad LifecycleEvent I check now the following (simplified):
if ($document instanceof List) {
foreach ($document->getElements() as $element) {
// at this moment $element->getId() is already defined but not yet loaded from mongo
$result = $this->elementRepository->findBy(array(‘_id’ => $element->getId()));
if (sizeof($result)==0) {
throw new InvalidElementInList($element->getId());
}
}
}
in the RestController this enables me now to catch this specific exception and to remove the invalid element from the list + to return a custom view to the user indicating that the element was removed.

Laravel queues & Persistent Variables across classes

There i am diving into the world of queues and all of its goodness and it hit me:
Session data is lost when the application pushes a task to the queue, due to serialization of information by laravel.
Having found out how to send data to queues, a question remains:
Given that the queue pushes information to a single class,
how do i make that information persistent(such as a session) across other classes throughout the duration of this task?
Coding Example:
//Case where the user object is needed by each class
class queueme {
...
//function called by queue
function atask($job,$data)
{
//Does xyz
if(isset($data['user_id'])
{
//Push user_id to another class
anotherclass::anothertask($data['user_id']);
}
}
}
class anotherclass {
...
function anothertask($user_id)
{
//Does abc
//Yup, that anotherofanother class needs user_id, we send it again.
anotherofanotherclass::yetanothertask($user_id);
}
}
The above code illustrates my problem.
Do i have to pass the $user_id or User object around, if my classes need this information?
Isn't there a cleaner way to do it?
When you queue up a job, you should pass all data required by the job to do its work. So if it's a job to resize a user's avatar, the necessary information required is the primary key of the user so we can pull their model out in the job. Just like if you're viewing a user's profile page in the browser, the necessary information (the user's primary key) is likely provided in the request URI (e.g. users/profile/{id}).
Sessions won't work for queue jobs, because sessions are used to carry state over from browser requests, and queue jobs are run by the system, so they simply don't exist. But that's fine, because it's not good practice for every class to be responsible for looking up data. The class that handles the request (a controller for an HTTP request, or a job class for a queue job) can take the input and look up models and such, but every call thereafter can pass those objects around.
Back to the user avatar example. You would pass the ID of the user as a primitive when queueing the job. You could pass the whole user model, but if the job is delayed for a long time, the state of that user could have changed in the meanwhile, so you'd be working with inaccurate data. And also, as you mention, not all objects can be serialised, so it's best to just pass the primary key to the job and it can pull it fresh from the database.
So queue your job:
Queue::push('AvatarProcessor', [$user->id]);
When your job is fired, pull the user fresh from the database and then you're able to pass it around to other classes, just like in a web request or any other scenario.
class AvatarProcessor {
public function fire($job, $data)
{
$user_id = $data[0]; // the user id is the first item in the array
$user = User::find($user_id); // re-pull the model from the database
if ($user == null)
{
// handle the possibility the user has been deleted since
// the job was pushed
}
// Do any work you like here. For an image manipulation example,
// we'll probably do some work and upload a new version of the avatar
// to a cloud provider like Amazon S3, and change the URL to the avatar
// on the user object. The method accepts the user model, it doesn't need
// to reconstruct the model again
(new ImageManipulator)->resizeAvatar($user);
$user->save(); // save the changes the image manipulator made
$job->delete(); // delete the job since we've completed it
}
}
As mentioned by maknz, the data needs to be passed explicitly to the job. But in the job handle() method, you can use session():
public function handle()
{
session()->put('query_id', 'H123214e890890');
Then your variable is directly accessible in any class:
$query_id = session()->get('query_id')

Doctrine setter method best practice for paired API call

I have a table that tracks a customer's status as stored in a third party database. My table should only be updated when I can successfully update the other database via an API call.
When using Doctrine, is it a bad practice to add the API call into the setter method in my entity class? For example:
public function setCustomerStatus( $cusotmerStatus )
{
$api = new externalApi();
if( $api->updateStatus( $customerStatus ) )
{
$this->customerStatus = $customerStatus;
}
else
{
return 'Could not update customer status';
}
}
If you have an Entity field that can only be set under a certain condition, you have two options; either make the check before the update:
if($api->updateStatus($customerStatus){
$entity->setCustomerStatus($customerStatus);
}
Or, make the check within the Entity, such as you have done in the set method. The advantage of containing it within the set method is that you don't leave room for error; unfamiliar developers may not know to run the check prior to calling the set method, or you just may forget. Therefore, if you can guarantee the check need always be made, I prefer the option you have chosen

Categories