🐘 🎯 Hexagonal Architecture, DDD & CQRS in PHP

Last update: Jun 25, 2022

🐘 🎯 Hexagonal Architecture, DDD & CQRS in PHP

codely.tv CodelyTV Courses Symfony 5.0 CI pipeline status

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

🚀 Environment Setup

🐳 Needed tools

  1. Install Docker
  2. Clone this project: git clone https://github.com/CodelyTV/php-ddd-example php-ddd-example
  3. Move to the project folder: cd php-ddd-example

🛠️ Environment configuration

  1. Create a local environment file (cp .env .env.local) if you want to modify any parameter

🔥 Application execution

  1. Install all the dependencies and bring up the project with Docker executing: make build
  2. Then you'll have 3 apps available (2 APIs and 1 Frontend):
    1. Mooc Backend: http://localhost:8030/health-check
    2. Backoffice Backend: http://localhost:8040/health-check
    3. Backoffice Frontend: http://localhost:8041/health-check

Tests execution

  1. Install the dependencies if you haven't done it previously: make deps
  2. Execute PHPUnit and Behat tests: make test

👩‍💻 Project explanation

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.

⛱️ Bounded Contexts

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

🎯 Hexagonal Architecture

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

Repository pattern

Our repositories try to be as simple as possible usually only containing 2 methods search and save. If we need some query with more filters we use the Specification pattern also known as Criteria pattern. So we add a searchByCriteria method.

You can see an example here and its implementation here.

Aggregates

You can see an example of an aggregate here. All aggregates should extend the AggregateRoot.

Command Bus

There is 1 implementations of the command bus.

  1. Sync using the Symfony Message Bus

Query Bus

The Query Bus uses the Symfony Message Bus.

Event Bus

The Event Bus uses the Symfony Message Bus. The MySql Bus uses a MySql+Pulling as a bus. The RabbitMQ Bus uses RabbitMQ C extension.

📱 Monitoring

Every time a domain event is published it's exported to Prometheus. You can access to the Prometheus panel here.

🤔 Contributing

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

🤩 Extra

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.

🎥 Used in the CodelyTV Pro courses:

GitHub

https://github.com/codelytv/php-ddd-example
Comments
  • 1. [Duda] ddd & doctrine

    Buenas chicos, antes de nada gran curso.

    Tengo una duda de concepto con respecto a ddd y como se manejaría con doctrine:

    Imaginémonos que tenemos una clase User (que todos sabemos que no para de crecer y crecer sin darnos cuenta) y queremos dividirla en contextos para evitar que la clase tenga toda la lógica centralizada de todos los casos de uso que se puedan dar, como lo resolveríais y como manejaríais el mapeo con doctrine?

    Por ejemplo imaginémonos una red social, user tiene cierta lógica que se aplica en la autenticación (registrar, login...) y luego otra lógica que se da en la parte de amigos (agregar amigo, borrar amigo...)

    Usaríais una clase abstracta BaseUser con las propiedades básicas del usuario (userId y username) y extenderíais de ella en función del contexto?, es posible manejar esto con doctrine?

    Gracias de antemano chicos ;)

    Reviewed by pana1990 at 2018-07-09 16:18
  • 2. [Question] Dominio o infraestructura

    Tenéis la interfaz middleware en infraestructura https://github.com/CodelyTV/cqrs-ddd-php-example/blob/master/src/Shared/Infrastructure/Bus/Middleware/Middleware.php

    Está clase no debería ir en dominio, enlazado a esto habría algún caso de uso que provocara tener una interfaz en infraestructura?¿

    Reviewed by pana1990 at 2019-07-26 13:51
  • 3. Crear grupo de discord o slack

    Estaría super bien crear un grupo de slack o discord en que los alumnos y algunos tutores podamos charlar de los distintos temas de la plataforma (ddd, tdd, php, symfony, docker...)

    Sorry de antemano si este no es el mejor lugar para comentar esto.

    Un abrazo chicos.

    Reviewed by pana1990 at 2019-08-23 11:43
  • 4. Dudas inicio proyecto

    Hola, quisiera que me ayudéis a identificar las rutas que hay en el proyecto, mas que nada para hacer mis pruebas y analizar todo para entenderlo bien.

    Solo me funciona estas dos: http://localhost:8030/health-check http://localhost:8030/courses-counter

    Pero si intento abrir cualquier otra, me da un error: {"code":"not_found_http_exception","message":"No route found for \u0022GET /courses\u0022"}

    No sé si hay posibilidad de ver el listado de cursos, por ejemplo. Otra pregunta ¿Hay login implementado?

    Y por último, una duda más: ¿Como puedo visualizar la BBDD? por ejemplo con phpmyadmin? no sé como hacerlo ¿Como puedo ver el rabbitmq?

    Gracias por adelantado y disculpad mi ignorancia, pero estoy empezando con todo esto.

    Reviewed by bareser at 2020-06-22 15:49
  • 5. Ejecutar en windows

    Hola chicos, soy un principiante y no tengo mucha idea, vuestra documentación para arrancar el proyecto creo que está basada en linux o mac, pero para lo que tenemos windows. ¿Algunas nociones básicas para poder echar a andar? Estoy intentado buscar información pero no me aclaro. Gracias de antemano.

    Reviewed by bareser at 2020-05-16 18:24
  • 6. Question about validation

    Hey, thanks a lot for the repo.

    I've tried to play with the repository and I wanted to see where would you do validation? I've created a video with a non existent course. I wonder how would you do if you wanted to validate that the course exists ?

    Thanks in advance :)

    Reviewed by anaelChardan at 2019-12-17 21:16
  • 7. Create Request/Response DTOs for Application Services

    What

    Instead of instantiating the Value Objects directly from the controller, we should instantiate a DTO such as SignUpUserRequest and pass it to the Application Service.

    The Application Services intended for querying data, we should return also a DTO such as UserResponse.

    Why

    This way we:

    • Avoid coupling our entry points to the internal details on how we model out our domain (UserId value objects and so on).
    • Leave the code on the Hexagonal Architecture approach closer to what we'll do while evolving to an architecture applying CQRS concepts. We will only need to:
      • Replace the XxxRequest by their corresponding XxxCommand,
      • Send the commands to the Command Bus instead of directly calling the Application Service
      • Implement the Command Handler in order to extract each one of the scalar values from the Command, convert them to Value Object instances, and call to the Application Service
      • Modify the Application Service in order to directly receive the Value Objects instead of the XxxRequest
    Reviewed by JavierCane at 2019-02-12 17:10
  • 8. Add Git pre-push hook

    Follow the same principles as in the Scala API repo

    You can copy the very same pre-push script just modifying the command to execute. That is, instead of calling to sbt prep, we should call to a command defined in the composer.json in order to run PhpStan, CodeSniffer, acceptance tests, and unit tests.

    This issue includes the addition to the README.md of this pre-push script as in the Scala API Repo 🙂

    Reviewed by JavierCane at 2018-10-08 11:37
  • 9. Error on make build

    Hi,

    I tried to run make build, but the execution report this error all the time. I'm using MAC Big Sur 11.4

    make: /bin/sh: Operation not permitted

    make: *** [Makefile:208: bcmath.lo] Error 127

    ERROR: Service 'backoffice_backend_php' failed to build : The command '/bin/sh -c apk --update upgrade && apk add --no-cache autoconf automake make gcc g++ bash icu-dev libzip-dev rabbitmq-c rabbitmq-c-dev && docker-php-ext-install -j$(nproc) bcmath opcache intl zip pdo_mysql' returned a non-zero code: 2 make: *** [start] Error 1

    Reviewed by alejandrozorita at 2021-07-03 12:46
  • 10. Issue running the project - No such file or directory

    Hi!

    When trying to install the project I get this message on all of the apps:

    Warning: file_put_contents(/app/apps/backoffice/backend/var/cache/test/CodelyTv_Apps_Backoffice_Backend_BackofficeBackendKernelTestDebugContainerDeprecations.log): Failed to open stream: No such file or directory

    Am I missing something? Ubuntu 20.04, currently running many projects with docker...

    image

    Reviewed by Pijuli at 2021-01-22 12:42
  • 11. Docker compose y ejercicios

    Desde hace unos días que estoy haciendo los ejercicios y en la parte de código PHP no he tenido excesivos problemas, pero a la hora de implementar por completo el VideoLike y mapear el fichero orm si que me da problemes.

    Por otra parte he añadido un docker-compose con tal de poder levantar un entorno de desarrollo en local

    Reviewed by sdecandelario at 2017-10-11 18:53
  • 12. fix: use request->get() instead of request->getAlpha()

    https://github.com/CodelyTV/php-ddd-example/commit/f7e7bed9c0596e4a5587559604c8731bc69a19cb broke some actions

    If we use request->getAlpha we loss some chars like dash, space, numbers, etc

    Reviewed by JoniJnm at 2021-12-05 17:48
  • 13. Add new Unit tests over CourseFinder

    Comprobamos que podamos obtener adecuadamente un curso. Para ello se ha realizado un test unitario sobre la clase CourseFinder comprobando los dos escenarios posibles:

    1. Que se haya obtenido el curso.
    2. Que no se haya obtenido nada.
    Reviewed by marcobarreche at 2021-10-22 18:06
Enraged Xenomorph - DDD/CQRS Symfony Application Boilerplate
Enraged Xenomorph - DDD/CQRS Symfony Application Boilerplate

Enraged Xenomorph - DDD/CQRS Symfony Application Boilerplate This project is very opinionated attempt to compile a bit of experience, few good practic

Jan 10, 2022
YCOM Impersonate. Login as selected YCOM user 🧙‍♂️in frontend.

YCOM Impersonate Login as selected YCOM user in frontend. Features: Backend users with admin rights or YCOM[] rights, can be automatically logged in v

Jan 19, 2022
POC d'un projet Clean Architecture + DDD

Proof Of Concept - Clean Architecture & DDD Installation Dans un premier temps, cloner le repository : git clone https://github.com/TBoileau/rse cd rs

Apr 9, 2022
Small convention based CQRS library for PHP

LiteCQRS for PHP Small naming-convention based CQRS library for PHP (loosely based on LiteCQRS for C#) that relies on the MessageBus, Command, EventSo

Jun 7, 2022
PHP Lightweight Message Bus supporting CQRS.
PHP Lightweight Message Bus supporting CQRS.

Prooph Service Bus PHP 7.1+ lightweight message bus supporting CQRS and Micro Services Important This library will receive support until December 31,

Jun 7, 2022
Demo project for the API Platform / DDD Workshop

Workshop DDD x API Platform This is a demo project used for the DDD x API Platform Workshop by @chalasr & @mtarld from @coopTilleuls. Checkout git clo

Jun 26, 2022
A DDD microservice did in laravel, to test infrastructure

A DDD microservice did in laravel, to test infrastructure

Feb 2, 2022
The game is implemented as an example of scalable and high load architecture combined with modern software development practices
The game is implemented as an example of scalable and high load architecture combined with modern software development practices

Crossword game The game is implemented as an example of scalable and high load architecture combined with modern software development practices Exampl

Jun 4, 2022
my personal example of Laravel clean architecture

what is this repo about Clean Architect Laravel ###run we assume docker desktop is up and running open up a terminal cd project directory run "cp .env

May 27, 2022
Detect flaws in your architecture, before they drag you down into the depths of dependency hell ...
Detect flaws in your architecture, before they drag you down into the depths of dependency hell ...

Detect flaws in your architecture before they drag you down into the depths of dependency hell ... What it does System Requirements Installation Phive

Jun 10, 2022
The Lucid Architecture for Scalable Laravel Applications.
The Lucid Architecture for Scalable Laravel Applications.

Website: https://lucidarch.dev Documentation: https://docs.lucidarch.dev Social: we share updates & interesting content from the web Twitter: @lucid_a

Jun 21, 2022
A research raw data repository for researchers of Arba Minch University built using Codeigniter which follows MVC architecture. The front-end is build using Bootstrap.

Arba Minch University Dataset Repository This system is a research dataset repository for Arba Minch University researchers and is build using Codeign

Jun 15, 2022
The Current US Version of PHP-Nuke Evolution Xtreme v3.0.1b-beta often known as Nuke-Evolution Xtreme. This is a hardened version of PHP-Nuke and is secure and safe. We are currently porting Xtreme over to PHP 8.0.3
The Current US Version of PHP-Nuke Evolution Xtreme v3.0.1b-beta often known as Nuke-Evolution Xtreme. This is a hardened version of PHP-Nuke and is secure and safe. We are currently porting Xtreme over to PHP 8.0.3

2021 Nightly Builds Repository PHP-Nuke Evolution Xtreme Developers TheGhost - Ernest Allen Buffington (Lead Developer) SeaBeast08 - Sebastian Scott B

Jun 10, 2022
A sampling profiler for PHP written in PHP, which reads information about running PHP VM from outside of the process.

Reli Reli is a sampling profiler (or a VM state inspector) written in PHP. It can read information about running PHP script from outside of the proces

Jun 18, 2022
PHP Meminfo is a PHP extension that gives you insights on the PHP memory content

MEMINFO PHP Meminfo is a PHP extension that gives you insights on the PHP memory content. Its main goal is to help you understand memory leaks: by loo

Jun 24, 2022
A multithreaded application server for PHP, written in PHP.

appserver.io, a PHP application server This is the main repository for the appserver.io project. What is appserver.io appserver.io is a multithreaded

Jun 23, 2022
Easy to use utility functions for everyday PHP projects. This is a port of the Lodash JS library to PHP

Lodash-PHP Lodash-PHP is a port of the Lodash JS library to PHP. It is a set of easy to use utility functions for everyday PHP projects. Lodash-PHP tr

May 31, 2022
A PHP 5.3+ and PHP 7.3 framework for OpenGraph Protocol

Opengraph Test with Atoum cd Opengraph/ curl -s https://getcomposer.org/installer | php php composer.phar install --dev ./vendor/atoum/atoum/bin/atoum

Feb 20, 2022
A status monitor for Elite Dangerous, written in PHP. Designed for 1080p screens in the four-panel-view in panel.php, and for 7 inch screens with a resolution of 1024x600 connected to a Raspberry Pi.

EDStatusPanel A status monitor for Elite Dangerous, written in PHP. Designed for 1080p screens in the four-panel-view in panel.php, and for 7 inch scr

Oct 15, 2021