Hexagonal Architecture, DDD & CQRS in PHP
Example of a PHP application using Domain-Driven Design (DDD) and Command Query Responsibility Segregation (CQRS) principles keeping the code as simple as possible.
Take a look, play and have fun with this. Stars are welcome
View Demo · Report a bug · Request a feature
- Install Docker
- Clone this project:
git clone https://github.com/CodelyTV/php-ddd-example php-ddd-example
- Move to the project folder:
- Create a local environment file (
cp .env .env.local) if you want to modify any parameter
- Install all the dependencies and bring up the project with Docker executing:
- Then you'll have 3 apps available (2 APIs and 1 Frontend):
- Install the dependencies if you haven't done it previously:
- Execute PHPUnit and Behat tests:
This project tries to be a MOOC (Massive Open Online Course) platform. It's decoupled from any framework, but it has some Symfony and Laravel implementations.
- Mooc: Place to look in if you wanna see some code
🙂. Massive Open Online Courses public platform with users, videos, notifications, and so on.
- Backoffice: Here you'll find the use cases needed by the Customer Support department in order to manage users, courses, videos, and so on.
This repository follows the Hexagonal Architecture pattern. Also, it's structured using
modules. With this, we can see that the current structure of a Bounded Context is:
$ tree -L 4 src src |-- Mooc // Company subdomain / Bounded Context: Features related to one of the company business lines / products | `-- Videos // Some Module inside the Mooc context | |-- Application | | |-- Create // Inside the application layer all is structured by actions | | | |-- CreateVideoCommand.php | | | |-- CreateVideoCommandHandler.php | | | `-- VideoCreator.php | | |-- Find | | |-- Trim | | `-- Update | |-- Domain | | |-- Video.php // The Aggregate of the Module | | |-- VideoCreatedDomainEvent.php // A Domain Event | | |-- VideoFinder.php | | |-- VideoId.php | | |-- VideoNotFound.php | | |-- VideoRepository.php // The `Interface` of the repository is inside Domain | | |-- VideoTitle.php | | |-- VideoType.php | | |-- VideoUrl.php | | `-- Videos.php // A collection of our Aggregate | `-- Infrastructure // The infrastructure of our module | |-- DependencyInjection | `-- Persistence | `--MySqlVideoRepository.php // An implementation of the repository `-- Shared // Shared Kernel: Common infrastructure and domain shared between the different Bounded Contexts |-- Domain `-- Infrastructure
Our repositories try to be as simple as possible usually only containing 2 methods
save. If we need some query with more filters we use the
Specification pattern also known as
Criteria pattern. So we add a
There is 1 implementations of the command bus.
- Sync using the Symfony Message Bus
The Query Bus uses the Symfony Message Bus.
Every time a domain event is published it's exported to Prometheus. You can access to the Prometheus panel here.
There are some things missing (add swagger, improve documentation...), feel free to add this if you want! If you want some guidelines feel free to contact us :)
This code was shown in the From framework coupled code to #microservices through #DDD talk and doubts where answered in the DDD y CQRS: Preguntas Frecuentes video.
🇪🇸DDD in PHP
🇪🇸CQRS: Command Query Responsibility Segregation
🇪🇸Comunicación entre microservicios: Event-Driven Architecture