Giter Club home page Giter Club logo

symfony-ddd-hexarch-cqrs's Introduction

Version Contributors Forks Stargazers Issues MIT License


symfony-ddd-hexarch-cqrs

Code examples and good practices using Domain Drive Development, Hexagonal Architecture, CQRS, Symfony 6, PHP8 and anything else I can think of...

Symfony 5 PHP Docker MySql SQLite

Report Bug · Request Feature


Build Status Coverage Status


Table of Contents
  1. About The Project
  2. Getting Started
  3. Roadmap
  4. Contributing
  5. License
  6. Contact
  7. Acknowledgements

About The Project

I have created this project to have a guide of code examples and good practices as a future reference for me and for anyone who may be interested.

I will be adding more examples that I think are interesting and that provide an extra for anyone who wants to get started in the technologies mentioned bellow.

Features

  • PHP8
  • Symfony 6
  • DDD guidelines
  • Hexagonal Architecture
  • SOLID
  • Docker
  • Doctrine ORM & DB migrations
  • Albums module with CQRS pattern (command and query bus)
  • Static code analysis: PHPCS, Rector, Psalm
  • Unit and integration tests: PHPUnit
  • Acceptance tests: Behat
  • Basic Authorization, with mandatory token to http POST endpoints
  • Basic JWT Authorization, with mandatory token to http PUT endpoints
  • NoSql: Redis examples
  • Frontend examples (React, Redux, Webpack, Babel, etc.): on this repo
  • Elastic stack (Elasticsearch, Logstash, Kibana, Filebeat)

Upcoming Features

  • Aggregates organization
  • Using native PHP amqp extension to publish events (instead of Symfony/Messenger)
  • RabbitMQ configuration wizard (queues and exchanges, retry, dead-letter and bindings)
  • Supervisor configuration wizard (file .ini per queue)

Getting Started

I will add new features and examples, this project is constantly evolving! You can see unreleased code at here

Prerequisites

Installation

Clone repo, download deps and create docker services:

git clone https://github.com/masfernandez/symfony-ddd-hexarch-cqrs.git
cd symfony-ddd-hexarch-cqrs
make composer-install
make up

Running prod env

Execute at root path:

make prod-start

Request examples

In order to create a new Album is mandatory to include a valid Token in request's Authorization header. So first, let's create a new User:

make create-demo-user
# Credentials for demo user: [email protected] 1234567890

Now, it's time to get a valid token:

curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/authentication' \
-H 'Content-Type: application/json' \
--data-raw '{
    "email": "[email protected]",
    "password": "1234567890"
}'

You can find the Token in response's Location header:

Server: nginx/1.19.5
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.0.0
Location: 4ac71eeda13c8fe7f0e4c017412bd9f2d886288cb8c88331007f2a9c7652385b
Cache-Control: no-cache, private
Date: Fri, 15 Jan 2021 11:23:45 GMT
X-Robots-Tag: noindex
Strict-Transport-Security: max-age=31536000

{}

We can publish new Albums now: (replace the value of the token here with the one you got before... obviously)

curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/albums' \
-H 'Authorization: Bearer 4ac71eeda13c8fe7f0e4c017412bd9f2d886288cb8c88331007f2a9c7652385b' \
-H 'Content-Type: application/json' \
--data-raw '{
    "id": "0da69030-3ed7-42b5-8aa5-25fb61dab1b2",
    "title": "Abbey Road",
    "release_date": "1969-09-26 00:00:00"  
}'

Verifying the Album created:

curl -X GET 'http://api.musiclabel.127.0.0.1.nip.io/albums?page[number]=1&page[size]=1&sort=title&fields[albums]=id,title,release_date'

We need a JWToken to make PUT operations on Albums, so let's get one:

curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/authentication/jwt' \
-H 'Content-Type: application/json' \
--data-raw '{
    "email": "[email protected]",
    "password": "1234567890"
}'

You can find the JWToken (header.payload.signature) in response's headers:

  • header+payload in Location header
  • signature in set-cookie header
HTTP/2 201 
server: nginx/1.19.8
content-type: application/json
location: header+payload:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwOi8vZXhhbXBsZS5vcmciLCJqdGkiOiJlWFZocHBTR0JwZllTeHNZIiwiaWF0IjoxNjE3MzU1NTMyLjQyNzU3MSwibmJmIjoxNjE3MzU1NTMzLjQyNzU3MSwiZXhwIjoxNjE3MzU5MTMyLjQyNzU3MSwidWlkIjoiMGY4MzNjMjItZmVmZC00ZmFmLWE3YzItNGEwNzlhMjJjMzdjIn0
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:25:32 GMT
x-robots-tag: noindex
set-cookie: signature=GFZiEgVkKIbv5YszK_5wKmhLpqlkhYUUS1N1nCLLavs; path=/; secure; httponly; samesite=none
strict-transport-security: max-age=31536000

You may be asking why sending the JWToken like this... well, I'm to lazy to write hundred of words when there is a lot of information already on there. Just few tips:

Recommend read:

Don't forget the purpose of this repo: just to show some examples, crazy dev ideas and my opinionated vision on how to approach some scenarios ;)

Let's replace Album created before:

The client (React, Vue, Curl, Postman... whatever) should know how to re-construct the JWToken to make a request (remember, header + payload in Authorization header and signature in cookie)

Note: replace the values of the token here with the one you got before... obviously

curl -i -X PUT 'http://api.musiclabel.127.0.0.1.nip.io/albums/0da69030-3ed7-42b5-8aa5-25fb61dab1b2' \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwOi8vZXhhbXBsZS5vcmciLCJqdGkiOiJlWFZocHBTR0JwZllTeHNZIiwiaWF0IjoxNjE3MzU1NTMyLjQyNzU3MSwibmJmIjoxNjE3MzU1NTMzLjQyNzU3MSwiZXhwIjoxNjE3MzU5MTMyLjQyNzU3MSwidWlkIjoiMGY4MzNjMjItZmVmZC00ZmFmLWE3YzItNGEwNzlhMjJjMzdjIn0' \
-H 'Content-Type: application/json' \
-H 'Cookie: signature=GFZiEgVkKIbv5YszK_5wKmhLpqlkhYUUS1N1nCLLavs' \
--data-raw '{
    "title": "New album value here",
    "release_date": "2021-04-02 00:00:00"
}'

Response:

HTTP/2 204 
server: nginx/1.19.8
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:58:22 GMT
x-robots-tag: noindex
strict-transport-security: max-age=31536000

Verifying the Album updated:

curl -i -X GET 'http://api.musiclabel.127.0.0.1.nip.io/albums?page[number]=1&page[size]=1&sort=title&fields[albums]=id,title,release_date'

Response:

HTTP/2 200 
server: nginx/1.19.8
content-type: application/json
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:59:36 GMT
x-robots-tag: noindex
strict-transport-security: max-age=31536000

{
    "data": [
        {
            "id": "0da69030-3ed7-42b5-8aa5-25fb61dab1b2",
            "title": "New album value here",
            "release_date": "2021-04-02 00:00:00"
        }
    ],
    "links": {
        "self": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
        "first": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
        "prev": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
        "next": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
        "last": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1"
    },
    "meta": {
        "total_pages": 1
    }
} 

Docker services

Several docker services will be available and ready for use when the app starts:

RabbitMQ

http://localhost:15672
user: rabbit_user
password: rabbit_pass

Kibana

http://localhost:5601

Kibana Nginx logs configuration:

Kibana Symfony logs configuration:

Logs can be visualized now at http://localhost:5601/app/logs/stream

Running dev env

make dev-start

Tests

make test

Docker info

There are several services in the Docker stack for this project. All services are built from official docker images except:

  • Nginx: Custom docker image. I will optimize some parameters soon but at this moment is just a wrapper of the official docker image. More info here
  • PHP-FPM: Custom docker image. It has 2 main targets, for production and development environment. Each env has some deps that you can check at here. This is also a repo I'm working on.

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE.txt for more information.

Contact

Miguel Ángel Sánchez Fernández - [email protected]

(linkedin hiden profile - require login)

LinkedIn

Project Link: https://github.com/masfernandez/symfony-ddd-hexarch-cqrs

Acknowledgements

Stats

symfony-ddd-hexarch-cqrs's People

Contributors

masfernandez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

symfony-ddd-hexarch-cqrs's Issues

Doesn't start without promtail .env

Installation section of readme says that first need to execute make composer-install and then make up. But if it's fresh installation without promtail .env file didn't work.
Here is out put of make composer-install command"

bdaler@BDALER-LAPTOP-HONOR:~/apps/symfony-ddd-hexarch-cqrs$ make composer-install
make[1]: Entering directory '/home/bdaler/apps/symfony-ddd-hexarch-cqrs'
ENV=dev docker-compose  \
        -f docker-compose.local.yml \
        -f docker-compose.local-prod.yml \
        -f docker-compose.local-dev.yml \
        up -d --remove-orphans
ERROR: Couldn't find env file: /home/bdaler/apps/symfony-ddd-hexarch-cqrs/docker/promtail/.env
make[1]: *** [Makefile:94: up-dev] Error 1
make[1]: Leaving directory '/home/bdaler/apps/symfony-ddd-hexarch-cqrs'
Error: No such container: docker-symfony-php
make: *** [Makefile:189: composer-install] Error 1

I suggest to add something @if [ ! -f docker/promtail/.env ]; then cp docker/promtail/.env.dist docker/promtail/.env; fi for create-env-file: in Makefile and first for fresh install execute this command.

...
## —— envs —————————————————————————————————————————————————————————————————
create-env-file:
	@if [ ! -f .env ]; then cp .env.dist .env; fi
+++	@if [ ! -f docker/promtail/.env ]; then cp docker/promtail/.env.dist docker/promtail/.env; fi
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.