🐘 🎯 Hexagonal Architecture, DDD & CQRS in PHP

Overview

🐘 🎯 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:

Comments
  • [Duda] ddd & doctrine

    [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 ;)

    opened by pana1990 23
  • [Question] Dominio o infraestructura

    [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?¿

    opened by pana1990 12
  • Crear grupo de discord o slack

    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.

    🤔 Question 
    opened by pana1990 11
  • Dudas inicio proyecto

    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.

    opened by bareser 8
  • Ejecutar en windows

    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.

    opened by bareser 8
  • Question about validation

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

    opened by anaelChardan 7
  • Create Request/Response DTOs for Application Services

    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
    todo :spiral_notepad: Stale Good first issue 
    opened by JavierCane 7
  • Add Git pre-push hook

    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 🙂

    Enhancement Hacktoberfest 
    opened by JavierCane 7
  • Error on make build

    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

    opened by alejandrozorita 5
  • Issue running the project - No such file or directory

    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

    opened by Pijuli 5
  • Docker compose y ejercicios

    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

    {▸} CodelyTV Pro solution 
    opened by sdecandelario 5
  • ADD: send tweet on new video post

    ADD: send tweet on new video post

    Hola! He añadido la funcionalidad de enviar un Tweet para promocionar un vídeo. Tengo la duda sobre una funcionalidad: a partir del id del vídeo, he creado un texto que incluye el nombre del curso con el que está relacionado, por lo que he tenido que ir al repositorio de cursos, pero hay dos que implementan la interface. Tenía las dudas:

    • Desde el dominio importar directamente el repositorio concreto (archivo o base de datos) a utilizar
    • Inyectar la interface CourseRepository en la capa aplicación y en services.yaml configurar el parámetro para decir a Symfony qué clase de las dos que instancian la interface debe utilizar (esta es la opción que he utilizado)

    ¡Muchas gracias!

    opened by falces 0
  • Elasticsearch + criteria pattern

    Elasticsearch + criteria pattern

    Buenas, a la hora de buscar con multiples "terms" o "wildcard" da un error de que la query esta mal formada: [term] query doesn't support multiple fields.

    En el código actual se monta una query parecida a esta:

    GET cursos/_search
    {
        "query": {
          "bool": {
            "must" :{
              "term":{
                "first_name" : "john",
                "middle_name" : "walter",
                "last_name" : "lastname",
                "email" : "[email protected]",
              }
            }
          }
        },
        "sort":{
          "created_at":{
            "order" : "DESC"
          }
        }
    }
    

    Y dentro del devtools ya te dice que no se puede hacer asi :(

    opened by rogerguasch 0
Owner
CodelyTV
Code examples for our software development videos and courses
CodelyTV
Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda.

Our Wedding Website Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda. ?

Edd Mann 3 Aug 21, 2022
Ecotone Framework is Service Bus Implementation. It enables message driven architecture and DDD, CQRS, Event Sourcing PHP

This is Read Only Repository To contribute make use of Ecotone-Dev repository. Ecotone is Service Bus Implementation, which enables message driven arc

EcotoneFramework 308 Dec 29, 2022
Dockerise Symfony Application (Symfony 6 + Clean Architecture+ DDD+ CQRS + Docker + Xdebug + PHPUnit + Doctrine ORM + JWT Auth + Static analysis)

Symfony Dockerise Symfony Application Install Docker Install Docker Compose Docker PHP & Nginx Create Symfony Application Debugging Install Xdebug Con

null 48 Jan 5, 2023
Clean Architecture, DDD and CQRS using Symfony 6

Task manager system using Clean Architecture, DDD and CQRS. Environment setup Install Docker Clone the project: git clone https://github.com/k0t9i/Tas

null 3 Sep 5, 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

Friends Of REDAXO 17 Sep 12, 2022
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

Gniewomir Świechowski 1 Jan 10, 2022
Orkestra is a library of infrastructure and architecture helpers for creating CQRS applications

Orkestra Orkestra is an opinionated framework with a plethora of recommendations on architectural design that we use internally at Morebec to develop

Morébec 2 Aug 18, 2021
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

Thomas Boileau 11 Sep 3, 2022
FFCMS 3 version core MVC architecture. Build-on use with ffcms main architecture builder.

FFCMS 3 version core MVC architecture. Build-on use with ffcms main architecture builder.

FFCMS 0 Feb 25, 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

Benjamin Eberlei 560 Nov 20, 2022
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,

null 440 Nov 20, 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

Les-Tilleuls.coop 34 Dec 16, 2022
A DDD microservice did in laravel, to test infrastructure

A DDD microservice did in laravel, to test infrastructure

pegons 3 Jul 8, 2022
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

Roman 56 Oct 27, 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

Sadegh Salari 37 Dec 23, 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 ... What it does System Requirements Installation Phive

Michael Haeuslmann 507 Dec 27, 2022
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

Lucid 256 Dec 25, 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

Wuletaw Wonte 8 Jul 1, 2022
Test and enforce architectural rules in your Laravel applications. Keep your app's architecture clean and consistent!

Laravel Arkitect Laravel Arkitect lets you test and enforce your architectural rules in your Laravel applications, and it's a PHPArkitect wrapper for

SMorteza Ebadi 55 Dec 17, 2022