DDD becomes more and more popular in PHP World and there are a lot of discussions on how to approach it.
In Laravel community it's getting momentum too.
Have you been wondering how can it be implemented in Laravel?
In this article I will explain basics of DDD building blocks and how can we use them in Laravel Application.
It's not required, however I encourage you to take a look on previous blog about CQRS "Going into CQRS with PHP" before starting.
Eloquent ORM and DDD
In DDD we are using Domain Models, which are different from Eloquent Models.
Domain Models are clean from infrastructure and Framework related implementation, in order to have full control over modifications and extensions.
Domain Models are meant to solve business related problems not technical ones.
Thanks to that it's easier to maintain and extend them.
If we decided to use Eloquent and mix it with Domain Model, then we've introduced database dependency.
However we did it for a reason, as we want to reap benefits that Eloquent integration brings.
Fighting your own framework may bring higher complexity into the code base and make increase maintainability cost.
For building Domain Models without Eloquent there will be a separate blog post, in this one we will focus on, what we can achieve, if we decided to go hand in hand with Eloquent ORM.
In DDD we build
Aggregates which are classes rich in behaviour.
As an example let's take
Article, which may be be
published, however first need to be
approved by the author.
This could be Eloquent Model, that we would store in database using
It's important to expose actions (methods) on the Aggregate and make use it as the only way to modify the data.
Calling insert and updates SQLs directly on the database, may introduce incorrect data or bypass our constraints.
If the only way to modify given aggregate is through his public methods and methods are protecting it's own state inside, then we come the place where our models are always valid.
The part of the model are Value Objects.
VO's are classes that are immutable. They are wrappers for given types that needs validation.
If we have Value Object like Email in system, then we can pass it around and be sure, it's always valid one. This decrease amount of guard logic within the system.
Enable Ecotone with Laravel
To enable Ecotone with Laravel install:
composer require ecotone/laravel
For automatic serialization and deserialization:
composer require ecotone/jms-converter
Eloquent Creating new Aggregate
We will implement
Issue aggregate. Issues can be reported by our customers in case of system errors.
Let's start by defining
In order to execute the
ReportIssue, we need to call
What comes from
$request->all() return data from
HTML Form which is:
["email" => "firstname.lastname@example.org","content" => "My PC is not working"]
ReportIssue is Value Object Class, so we need to know how to convert from
Ecotone JMS Converter package will handle all deserialization from Arrays / JSON / XML to PHP classes and other way around.
Let's implement our Eloquent
- We mark our Model with
#[Aggregate]so Ecotone can find it
- We enable factory method under
- As we want to publish event which contains
Idwe need to save
Issueinside the factory method, so the identifier will be assigned
- We publish
recordThatmethod, which comes from
- We need to expose public method with identifier for Ecotone
Now we can execute our
Controller we have defined previously to send Command and create new Issue.
Changing The Aggregate Issue
Now we can add possibility to close the Issue.
There is no Command Class defined for Command Handler and that's because we do not need any data in here. When needed Ecotone allows for seamless routing to given Handlers by routing name only.
Now we want to execute this Command Handler
metadata part are extra information, that are not part of the Command itself.
Ecotone use it to pass around framework related information.
aggregate.id we tell Ecotone which
Issue Aggregate it should execute.
You may use metadata to pass your own extra details that you would like to pass alongside with Command for example
Issue aggregate was reported we are publishing event:
We can register subscriber, that will send Email with confirmation to the customer after Issue was reported.
subscribe to specific Event we type hint given class as first parameter (just like with Command Handler) and mark method with
Ecotone Framework is handling glue code and providing building blocks, so we can build applications quickly and in solid way.
It integrates with Laravel and Eloquent in way those Frameworks were designed.
And in case of need allow you to extend your application with new functionalities like Event Sourcing and Asynchronous communication.
If you want to run Demo Application with
Laravel and Ecotone you can find it under this repository.