Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/robiningelbrecht/php-slim-skeleton
An event-driven Slim 4 Framework skeleton using AMQP and CQRS
https://github.com/robiningelbrecht/php-slim-skeleton
amqp cqrs ddd slim-framework slim4 website
Last synced: 2 months ago
JSON representation
An event-driven Slim 4 Framework skeleton using AMQP and CQRS
- Host: GitHub
- URL: https://github.com/robiningelbrecht/php-slim-skeleton
- Owner: robiningelbrecht
- License: mit
- Created: 2022-07-29T06:11:21.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2023-08-29T13:12:05.000Z (over 1 year ago)
- Last Synced: 2024-10-14T05:55:13.419Z (3 months ago)
- Topics: amqp, cqrs, ddd, slim-framework, slim4, website
- Language: PHP
- Homepage: https://php-slim-skeleton.robiningelbrecht.be/
- Size: 4.11 MB
- Stars: 42
- Watchers: 3
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Event-driven Slim 4 Framework skeleton
---
An event-driven Slim 4 Framework skeleton using AMQP and CQRS## Installation
### Default installation profile
The default installation profile has no examples. You should be using this profile if you know what's up and want to start with a clean slate.
```bash
> composer create-project robiningelbrecht/php-slim-skeleton [app-name] --no-install --ignore-platform-reqs --stability=dev
# Build docker containers
> docker-compose up -d --build
# Install dependencies
> docker-compose run --rm php-cli composer install
```### Full installation profile
The full installation profile has a complete working example.
```bash
> composer create-project robiningelbrecht/php-slim-skeleton:dev-master-with-examples [app-name] --no-install --ignore-platform-reqs --stability=dev
# Build docker containers
> docker-compose up -d --build
# Install dependencies
> docker-compose run --rm php-cli composer install
# Initialize example
> docker-compose run --rm php-cli composer example:init
# Start consuming the voting example queue
> docker-compose run --rm php-cli bin/console app:amqp:consume add-vote-command-queue
```## Some examples
### Registering a new route
```php
namespace App\Controller;class UserOverviewRequestHandler
{
public function __construct(
private readonly UserOverviewRepository $userOverviewRepository,
) {
}public function handle(
ServerRequestInterface $request,
ResponseInterface $response): ResponseInterface
{
$users = $this->userOverviewRepository->findonyBy(/*...*/);
$response->getBody()->write(/*...*/);return $response;
}
}
```Head over to `config/routes.php` and add a route for your RequestHandler:
```php
return function (App $app) {
// Set default route strategy.
$routeCollector = $app->getRouteCollector();
$routeCollector->setDefaultInvocationStrategy(new RequestResponseArgs());
$app->get('/user/overview', UserOverviewRequestHandler::class.':handle');
};
```
[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/request-handlers)### Console commands
The console application uses the Symfony console component to leverage CLI functionality.
```php
#[AsCommand(name: 'app:user:create')]
class CreateUserConsoleCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
// ...
return Command::SUCCESS;
}
}
```[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/console-commands)
### Domain commands and command handlers
The skeleton allows you to use commands and command handlers to perform actions.
These 2 always come in pairs, when creating a new command in the write model, a corresponding command handler has to be created as well.#### Creating a new command
```php
namespace App\Domain\WriteModel\User\CreateUser;class CreateUser extends DomainCommand
{
}
```#### Creating the corresponding command handler
```php
namespace App\Domain\WriteModel\User\CreateUser;#[AsCommandHandler]
class CreateUserCommandHandler implements CommandHandler
{
public function __construct(
) {
}public function handle(DomainCommand $command): void
{
assert($command instanceof CreateUser);// Do stuff.
}
}
```[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/cqrs)
### Eventing
The idea of this project is that everything is, or can be, event-driven. Event sourcing is not provided by default.
#### Create a new event
```php
class UserWasCreated extends DomainEvent
{
public function __construct(
private UserId $userId,
) {
}public function getUserId(): UserId
{
return $this->userId;
}
}
```#### Record the event
```php
class User extends AggregateRoot
{
private function __construct(
private UserId $userId,
) {
}public static function create(
UserId $userId,
): self {
$user = new self($userId);
$user->recordThat(new UserWasCreated($userId));return $user;
}
}
```#### Publish the event
```php
class UserRepository extends DbalAggregateRootRepository
{
public function add(User $user): void
{
$this->connection->insert(/*...*/);
$this->publishEvents($user->getRecordedEvents());
}
}
```#### Listen to the event
```php
#[AsEventListener(type: EventListenerType::PROCESS_MANAGER)]
class UserNotificationManager extends ConventionBasedEventListener
{
public function reactToUserWasCreated(UserWasCreated $event): void
{
// Send out some notifications.
}
}
```[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/eventing)
### Async processing of commands with RabbitMQ
The chosen AMQP implementation for this project is RabbitMQ, but it can be easily switched to for example Amazon's AMQP solution.
#### Registering new queues
```php
#[AsEventListener(type: EventListenerType::PROCESS_MANAGER)]
class UserCommandQueue extends CommandQueue
{
}
```#### Queueing commands
```php
class YourService
{
public function __construct(
private readonly UserCommandQueue $userCommandQueue
) {
}public function aMethod(): void
{
$this->userCommandQueue->queue(new CreateUser(/*...*/));
}
}
```#### Consuming your queue
```bash
> docker-compose run --rm php-cli bin/console app:amqp:consume user-command-queue
```[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/amqp)
### Database migrations
To manage database migrations, the doctrine/migrations package is used.
```php
#[Entity]
class User extends AggregateRoot
{
private function __construct(
#[Id, Column(type: 'string', unique: true, nullable: false)]
private readonly UserId $userId,
#[Column(type: 'string', nullable: false)]
private readonly Name $name,
) {
}// ...
}
```You can have Doctrine generate a migration for you by comparing the current state of your database schema
to the mapping information that is defined by using the ORM and then execute that migration.```bash
> docker-compose run --rm php-cli vendor/bin/doctrine-migrations diff
> docker-compose run --rm php-cli vendor/bin/doctrine-migrations migrate
```[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/migrations)
### Templating engine
The template engine of choice for this project is Twig and can be used to render anything HTML related.
#### Create a template
```twig
Users
- {{ user.username|e }}
{% for user in users %}
{% endfor %}
```
#### Render the template
```php
class UserOverviewRequestHandler
{
public function __construct(
private readonly Environment $twig,
) {
}
public function handle(
ServerRequestInterface $request,
ResponseInterface $response): ResponseInterface
{
$template = $this->twig->load('users.html.twig');
$response->getBody()->write($template->render(/*...*/));
return $response;
}
}
```
[Full documentation](https://php-slim-skeleton.robiningelbrecht.be/development-guide/templating)
## Documentation
Learn more at these links:
- [Skeleton Documentation](https://php-slim-skeleton.robiningelbrecht.be/)
- [Slim framework](https://www.slimframework.com)
- [PHP-DI](https://php-di.org/)
- [Symfony Console Commands](https://symfony.com/doc/current/console.html)
- [Doctrine migrations](https://www.doctrine-project.org/projects/doctrine-migrations/en/3.6/)
- [Twig](https://twig.symfony.com/)
## Projects using this skeleton
- [Unofficial World Cube Association (WCA) Public API](https://github.com/robiningelbrecht/wca-rest-api)
- [Database of newly generated Pokemon cards using GPT and Stable Diffusion](https://github.com/robiningelbrecht/gotta-generate-em-all)
- [A PHP app that generates Pokemon cards by using GPT and Stable Diffusion](https://github.com/robiningelbrecht/pokemon-card-generator)
- [Generate Full 3D pictures of a Rubiks cube](https://github.com/robiningelbrecht/puzzle-generator)
## Contributing
Please see [CONTRIBUTING](https://php-slim-skeleton.robiningelbrecht.be/contribute) for details.