php ddd example

๐Ÿ˜๐ŸŽฏ Hexagonal Architecture + DDD + CQRS in PHP using Symfony 5

2067
767
PHP

Codely logo

๐Ÿ˜๐ŸŽฏ Hexagonal Architecture, DDD & CQRS in PHP

codely.tv CodelyTV Courses Symfony 6 Type Coverage 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:

๐ŸŒ remember to visit our courses