How to get data back from a command bus? - php

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.

Related

How to get the created object in controller when implementing CQRS

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).

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.

Controller as Service - How to pass and return values in an advanced case?

Using Symfony, I am displaying a table with some entries the user is able to select from. There is a little more complexity as this might include calling some further actions e. g. for filtering the table entries, sorting by different criteria, etc.
I have implemented the whole thing in an own bundle, let's say ChoiceTableBundle (with ChoiceTableController). Now I would like to be able to use this bundle from other bundles, sometimes with some more parametrization.
My desired workflow would then look like this:
User is currently working with Bundle OtherBundle and triggers chooseAction.
chooseAction forwards to ChoiceTableController (resp. its default entry action).
Within ChoiceTableBundle, the user is able to navigate, filter, sort, ... using the actions and routing supplied by this bundle.
When the user has made his choice, he triggers another action (like choiceFinishedAction) and the control flow returns to OtherBundle, handing over the results of the users choice.
Based on these results, OtherBundle can then continue working.
Additionally, OtherOtherBundle (and some more...) should also be able to use this workflow, possibly passing some configuration values to ChoiceTableBundle to make it behave a little different.
I have read about the "Controller as Service" pattern of Symfony 2 and IMHO it's the right approach here (if not, please tell me ;)). So I would make a service out of ChoiceTableController and use it from the other bundles. Anyway, with the workflow above in mind, I don't see a "good" way to achieve this:
How can I pass over configuration parameters to ChoiceTableBundle (resp. ChoiceTableController), if neccessary?
How can ChoiceTableBundle know from where it was called?
How can I return the results to this calling bundle?
Basic approaches could be to store the values in the session or to create an intermediate object being passed. Both do not seem particularly elegant to me. Can you please give me a shove in the right direction? Many thanks in advance!
The main question is if you really need to call your filtering / searching logic as a controller action. Do you really need to make a request?
I would say it could be also doable just by passing all the required data to a service you define.
This service you should create from the guts of your ChoiceTableBundleand let both you ChoiceTableBundle and your OtherBundle to use the extracted service.
service / library way
// register it in your service container
class FilteredDataProvider
{
/**
* #return customObjectInterface or scallar or whatever you like
*/
public function doFiltering($searchString, $order)
{
return $this->filterAndReturnData($searchString, $order)
}
}
...
class OtherBundleController extends Controller {
public function showStuffAction() {
$result = $this->container->get('filter_data_provider')
->doFiltering('text', 'ascending')
}
}
controller way
The whole thing can be accomplished with the same approach as lipp/imagine bundle uses.
Have a controller as service and call/send all the required information to that controller when you need some results, you can also send whole request.
class MyController extends Controller
{
public function indexAction()
{
// RedirectResponse object
$responeFromYourSearchFilterAction = $this->container
->get('my_search_filter_controller')
->filterSearchAction(
$this->request, // http request
'parameter1' // like search string
'parameterX' // like sorting direction
);
// do something with the response
// ..
}
}
A separate service class would be much more flexible. Also if you need other parameters or Request object you can always provide it.
Info how to declare controller as service is here:
http://symfony.com/doc/current/cookbook/controller/service.html
How liip uses it:
https://github.com/liip/LiipImagineBundle#using-the-controller-as-a-service

Symfony2 Service Response

i was trying to setup a general service which handles common function i use very often everywhere in my project. For example if a user wants to purchase something for virtual currency there would be a function which checks, if the user has enough virtual currency in his account.
If the user doesnt have enough virtual currency I want this function to make a JSOn Response, but of cource, only controllers are allowed to response. But this means i have to check in every action I use this function, whether the purchase is valid or not.
Here is the function call in my Controller:
$purchaes= $this->get('global_functions')->payVirtualCurrency($user_id, $currency_amount);
if($change instanceof JsonResponse){
return $change;
}
And the function:
public function payVirtualCurrency($user_id, $currency_amount){
$user = $this->dm->getRepository('LoginBundle:User')->findOneById($user_id);
if($user->getVirtualCurrency() < $currency_amount){
return new JsonResponse(array('error' => $this->trans->trans('Insufficient amount of virtual Currency')));
}
return true;
}
Is there a better way to do this? I really want to avoid doing the same thing in the controller over and over again.
Thanks in advance!
Two options come to my mind, both are quite elegant solutions but both require little work:
1. Create custom exception listener
Create custom exception, let's call it InsufficientMoneyException. Then, your sevice can be as it is, but instead of returning response it throws your custom exception (in case user does not have enough money). Then, you create custom exception listener which listenes to InsufficientMoneyException custom exception and returns your desired JsonResponse.
2. Create custom annotation
You can create custom annotation and flag a controller action with this annotation. It would look something like this
/**
* #MinimumMoneyRequired("50")
*/
public function buyAction()
{
(...)
}
This option is really nice and decoupled but it require quite a lot of configuration. This is nice blog post with detailed description how to create custom annotations

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')

Categories