Skip to content

Commit

Permalink
Merge pull request #25 from yceruto/context
Browse files Browse the repository at this point in the history
Update project structure for DDD approach and Hexagonal Arch
  • Loading branch information
yceruto authored Feb 25, 2022
2 parents 5063019 + 32d0c12 commit 80c325e
Show file tree
Hide file tree
Showing 19 changed files with 206 additions and 123 deletions.
87 changes: 56 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
# Symfony 5 skeleton with Virtual Kernel for multiple applications
# Symfony 5 project skeleton for multiple applications

This project skeleton is built for [Domain-Driven Design](https://en.wikipedia.org/wiki/Domain-driven_design) approach
and [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)). It is also applicable to [microservice](https://en.wikipedia.org/wiki/Microservices) architecture.

### Installation

composer create-project yceruto/symfony-skeleton ddd

### Context-based Virtual Kernel
### Context-based Kernel

The term "Virtual Kernel" refers to the practice of running more than one application (such as `api.example.com` and `admin.example.com`) on a single project repository. Virtual kernels are "context-based", meaning that you have multiple kernel (with different context) running on the same project. The fact that they are running on the same physical repository is not apparent to the end user.
The term refers to the practice of running (at the same time) more than one application with different contexts
(such as `api.example.com` and `admin.example.com`) on a single project repository. The fact that they are running on the
same physical repository is not apparent to the end user.

In short, each kernel context corresponds to one application.

### Application-based Configuration
### Context-based Configuration

The idea is to replicate the default project structure for each application, which is represented by a subdirectory with the context of the virtual kernel. It should look like this:
The project structure contains a new `context/` directory where the config and presentation subjects are placed per kernel context,
and the `src/` directory hosts the core functionalities divided by modules:

├── config/
│ ├── admin/
│ │ ├── packages/
│ │ ├── bundles.php
│ │ ├── routes.yaml
│ │ ├── security.yaml
│ │ └── services.yaml
│ ├── api/
│ ├── site/
│ ├── packages/
│ ├── bundles.php
│ └── services.yaml
├── context/
│ ├── admin/
│ │ ├── config/
│ │ │ ├── packages/
│ │ │ ├── bundles.php
│ │ │ ├── routes.yaml
│ │ │ ├── security.yaml
│ │ │ └── services.yaml
│ │ └── src/
│ │ ├── Command/
│ │ └── Controller/
│ ├── api/
│ ├── site/
│ └── Kernel.php
├── src/
│ ├── Admin/
│ ├── Api/
│ ├── Site/
│ ├── Module/
│ │ └── SubModule/
│ │ ├── Application/
│ │ ├── Domain/
│ │ └── Infrastructure/
│ ├── Shared/
│ └── Kernel.php
│ │ ├── Domain/
│ │ ├── Infrastructure/
│ │ └── Presentation/
├── var/
│ ├── cache/
│ │ ├── admin/
Expand All @@ -41,16 +57,21 @@ The idea is to replicate the default project structure for each application, whi
│ │ └── site/
│ └── logs/

There `admin`, `api` and `site` directories are part of this multiple kernel approach, and they will contain all what is only needed for each app. Whereas `packages/`, `bundles.php` and any other dir/file at root of the `config` will be recognized as global config for all apps.
There `admin`, `api` and `site` directories are part of this kernel context approach, and they will contain all what is
only needed for each context. Whereas `packages/`, `bundles.php` and any other dir/file at root of the `config` will be
recognized as global config for all contexts.

As a performance key, each app (by definition) has its own DI container file, routes and configuration, while sharing common things too like vendors, config and src code.
As a performance key, each app (by definition) has its own DI container file, routes and configuration, while sharing
common things too like `vendor`, `config` and `src` code.

### Keeping one entry point for all applications

├── public/
│ └── index.php

Following the same philosophy since Symfony 4, as well as you can set environment variables to decide the app mode (dev/test/prod) and whether debug mode is enabled you must create a new environment variable `APP_CONTEXT` to specify the app you want to run. Lets playing with it using the PHP's built-in Web server:
Following the same philosophy since Symfony 4, as well as you can set environment variables to decide the app mode
(dev/test/prod) and whether debug mode is enabled you must create a new environment variable `APP_CONTEXT` to specify
the kernel context you want to run. Lets playing with it using the PHP's built-in Web server:

$ APP_CONTEXT=admin php -S 127.0.0.1:8000 -t public
$ APP_CONTEXT=api php -S 127.0.0.1:8001 -t public
Expand All @@ -61,9 +82,10 @@ You will need to use [Symfony local server](https://symfony.com/doc/current/setu

First, start Symfony proxy by doing `symfony proxy:start` in the project folder.

Then, create a [symlink](https://en.wikipedia.org/wiki/Symbolic_link) pointing to your project folder for each of your applications. You can keep them in a folder in your project or outside it, as you prefer.
Then, create a [symlink](https://en.wikipedia.org/wiki/Symbolic_link) pointing to your project folder for each of your
applications. You can keep them in a folder in your project or outside it, as you prefer.

├── applications/
├── links/
│ ├── admin
| ├── api
| └── site
Expand All @@ -75,16 +97,16 @@ Next, you'll need to configure each local server and start it. To do so, you wil

```
# start admin local server
APP_CONTEXT=admin symfony proxy:domain:attach admin --dir=[project folder path]/applications/admin
APP_CONTEXT=admin symfony server:start --dir=[project folder path]/applications/admin
APP_CONTEXT=admin symfony proxy:domain:attach admin --dir=[project folder path]/links/admin
APP_CONTEXT=admin symfony server:start --dir=[project folder path]/links/admin
# start api local server
APP_CONTEXT=api symfony proxy:domain:attach api --dir=[project folder path]/applications/api
APP_CONTEXT=api symfony server:start --dir=[project folder path]/applications/api
APP_CONTEXT=api symfony proxy:domain:attach api --dir=[project folder path]/links/api
APP_CONTEXT=api symfony server:start --dir=[project folder path]/links/api
# start site local server
APP_CONTEXT=site symfony proxy:domain:attach site --dir=[project folder path]/applications/site
APP_CONTEXT=site symfony server:start --dir=[project folder path]/applications/site
APP_CONTEXT=site symfony proxy:domain:attach site --dir=[project folder path]/links/site
APP_CONTEXT=site symfony server:start --dir=[project folder path]/links/site
```

To check if each server is running, you can go to [localhost:7080](http://localhost:7080).
Expand Down Expand Up @@ -135,7 +157,8 @@ Also, you can configure the default `APP_CONTEXT` environment variable in your `
│ │ └── AdminWebTestCase.php
│ ├── Api/

The `tests` directory is pretty similar to `src` directory, just update your `composer.json` and map each directory `tests/<CONTEXT>/` with its PSR-4 namespace:
The `tests` directory is pretty similar to `src` directory, just update your `composer.json` and map each directory
`tests/<CONTEXT>/` with its PSR-4 namespace:

"autoload-dev": {
"psr-4": {
Expand All @@ -152,8 +175,10 @@ Here, creates a `<CONTEXT>WebTestCase` class per app in order to execute all tes

Run `bin/console make:app-context <CONTEXT>` to create a new application context skeleton.

Note: After install any new package that generate a new configuration file (into the common `config/packages` directory) make sure to move it to the correct sub-app directory if it is not intended to work for all applications.
Also, you should update the `auto-scripts` section in `composer.json` to execute each command with the right kernel option, and it's also recommended having the script `"cache:clear -k <CONTEXT>": "symfony-cmd"` for each app.
Note: After install any new package that generate a new configuration file (into the common `config/packages` directory)
make sure to move it to the correct sub-app directory if it is not intended to work for all applications. Also, you should
update the `auto-scripts` section in `composer.json` to execute each command with the right kernel option, and it's also
recommended having the script `"cache:clear -k <CONTEXT>": "symfony-cmd"` for each app.

License
-------
Expand Down
13 changes: 7 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"symfony/yaml": "5.*"
},
"require-dev": {
"yceruto/ddd-maker-bundle": "^1.0"
"yceruto/ddd-maker-bundle": "^1.1"
},
"config": {
"optimize-autoloader": true,
Expand All @@ -30,16 +30,16 @@
},
"autoload": {
"classmap": [
"src/Kernel.php"
"context/Kernel.php"
],
"psr-4": {
"App\\": "src/App/",
"Shared\\": "src/Shared/"
"Core\\": "src/",
"App\\": "context/app/src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/App/"
"App\\Tests\\": "tests/context/app/"
}
},
"replace": {
Expand All @@ -60,7 +60,8 @@
]
},
"conflict": {
"symfony/symfony": "*"
"symfony/symfony": "*",
"yceruto/ddd-maker-bundle": "<1.1"
},
"extra": {
"symfony": {
Expand Down
Loading

0 comments on commit 80c325e

Please sign in to comment.