Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mrhdolek/slim4-boirlerplate
Template for a project based on the slim framework
https://github.com/mrhdolek/slim4-boirlerplate
amqp ddd doctrine hactoberfest hactoberfest-accepted hactoberfest2023 microservices phpunit rabbitmq slim slim4 slim4-doctrine slim4-framework slim4-skeleton swoole
Last synced: 6 days ago
JSON representation
Template for a project based on the slim framework
- Host: GitHub
- URL: https://github.com/mrhdolek/slim4-boirlerplate
- Owner: MrHDOLEK
- License: mit
- Created: 2023-05-26T14:08:20.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-06-18T13:06:31.000Z (5 months ago)
- Last Synced: 2024-10-30T15:06:12.005Z (6 days ago)
- Topics: amqp, ddd, doctrine, hactoberfest, hactoberfest-accepted, hactoberfest2023, microservices, phpunit, rabbitmq, slim, slim4, slim4-doctrine, slim4-framework, slim4-skeleton, swoole
- Language: PHP
- Homepage:
- Size: 385 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
- Code of conduct: .github/CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# Slim 4 Framework skeleton
![Slim](slim.webp)
[![CI](https://github.com/MrHDOLEK/slim4-boirlerplate/actions/workflows/php.yml/badge.svg?branch=main)](https://github.com/MrHDOLEK/slim4-boirlerplate/actions/workflows/php.yml)
[![Codecov.io](https://codecov.io/gh/MrHDOLEK/slim4-boirlerplate/graph/badge.svg?token=KKBMW5HJVM)](https://codecov.io/gh/MrHDOLEK/slim4-boirlerplate)
[![License](https://img.shields.io/github/license/robiningelbrecht/slim-skeleton-ddd-amqp?color=428f7e&logo=open%20source%20initiative&logoColor=white)](https://github.com/MrHDOLEK/slim4-boirlerplate/blob/master/LICENSE)
[![PHPStan Enabled](https://img.shields.io/badge/PHPStan-level%205-succes.svg?logo=php&logoColor=white&color=31C652)](https://phpstan.org/)
[![PHP](https://img.shields.io/packagist/php-v/mrhdolek/slim4-boirlerplate/dev-main?color=%23777bb3&logo=php&logoColor=white)](https://php.net/)---
#### An Slim 4 Framework skeleton using AMQP and DDDI was inspired to create this skeleton from: [robiningelbrecht](https://github.com/robiningelbrecht).
## Project setup
### Development
If you have problems with permissions please add sudo before make example:
- `sudo make install`
- `sudo make start`
### Run env for Mac/Linux- `make install`
- `make start`
- `make db-create`### Run env for Windows
Please install packages makefile for [Windows](http://gnuwin32.sourceforge.net/packages/make.htm)
- `make install`
- `make start`
- `make db-create`### Address where the environment is available
- `http://localhost`
## Documentation for a Rest Api
- `http://localhost/docs/v1`
## RabbitMq dashboard
- `http://localhost:15672`
## All commands- `make help`
## Some examples
### Registering a new route
```php
namespace App\Application\Actions\User;class GetAllUsersAction extends UserAction
{
public function __construct(
private readonly UserService $userService,
protected LoggerInterface $logger,
) {
parent::__construct($logger);
}protected function action(): Response
{
$user = $this->userService->getAllUsers();return $this->respondWithJson(new UsersResponseDto($user));
}
}
```Head over to `config/routes.php` and add a route for your RequestHandler:
```php
return function (App $app) {
$group->get("/users", GetAllUsersAction::class)
->setName("getAllUsers");
};
```### 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;
}
}
```### Scheduling Commands
To schedule a command, we use the GO\Scheduler class. This class allows us to define the timing and frequency of command execution. Here's an example of how to schedule a command to run daily:
```php
$scheduler = new GO\Scheduler();
$scheduler->php('/path/to/command app:user:create')->daily();
$scheduler->run();
```
In this example, the app:user:create command is scheduled to run every day.#### Running the Scheduler
The scheduler should be triggered by a system cron job to ensure it runs at regular intervals. Typically, you would set up a cron job to execute a PHP script that initializes and runs the scheduler.For instance, a cron job running every minute might look like this:
```bash
* * * * * ./bin/console.php schedule
```This setup ensures that your scheduled commands are executed reliably and on time.
### Domain event and event handlers
The framework implements the amqp protocol with handlers that allow events to be easily pushed onto the queue.
Each event must have a handler implemented that consumes the event.#### Creating a new event
```php
class UserWasCreated extends DomainEvent
{
}
```#### Creating the corresponding event handler
```php
namespace App\Domain\Entity\User\DomainEvents;#[AsEventHandler]
class UserWasCreatedEventHandler implements EventHandler
{
public function __construct(
) {
}public function handle(DomainEvent $event): void
{
assert($event instanceof UserWasCreated);// Do stuff.
}
}
```### Eventing
#### Create a new event
```php
class UserWasCreated extends DomainEvent
{
public function __construct(
private UserId $userId,
) {
}public function getUserId(): UserId
{
return $this->userId;
}
}
```### 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
#[AsAmqpQueue(name: "user-command-queue", numberOfWorkers: 1)]
class UserEventQueue extends EventQueue
{
}
```#### Queueing events
```php
final readonly class UserEventsService
{
public function __construct(
private UserEventQueue $userEventQueue,
) {}public function userWasCreated(User $user): void
{
$this->userEventQueue->queue(new UserWasCreated($user));
}
}
```#### Consuming your queue
```bash
> docker-compose run --rm php bin/console.php app:amqp:consume user-command-queue
```### Create new entity
If you have created a new entity and want to map it to a database you must create a xml in src/Infrastructure/Persistence/Doctrine/Mapping .
It must be named so as to indicate where exactly the entity to be mapped is located.### Binding of interfaces/Registry global objects
To register a dependency or create a single configured global instance, you need to go to config/container.php
### Mapping database data to custom objects
To map data from a database to a custom object you need to extend something from Doctrine/DBAL/Types .
```php
use App\Domain\ValueObject\UserType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\StringType;class UserTypeType extends StringType
{
const TYPE_NAME = 'UserType';public function convertToPHPValue($value, AbstractPlatform $platform): ?UserType
{
return null !== $value ? UserType::fromString($value) : null;
}public function getName()
{
return self::TYPE_NAME;
}
}
```After extending, you need to add a note in the xml that you are mapping a field to an object.
```xml
```Finally, you must add the new type in config/container.php where doctrine is configured
```php
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\Setup;return [
...
EntityManager::class => function (Settings $settings): EntityManager {
$config = Setup::createXMLMetadataConfiguration(
$settings->get("doctrine.metadata_dirs"),
$settings->get("doctrine.dev_mode"),
);
if (!Type::hasType('UserType')) {
Type::addType('UserType', UserTypeType::class);
}
return EntityManager::create($settings->get("doctrine.connection"), $config);
},
...
];```
### Database migrations
To manage database migrations, the doctrine/migrations package is used.
```xml
utf8mb4_polish_ci
```
The mapping is done using a yaml which maps your entities from the domain to a structure in the database .
If you change something in yaml, you can use the commands below to generate a migration based on the difference.```bash
> docker-compose run --rm php vendor/bin/doctrine-migrations diff
> docker-compose run --rm php vendor/bin/doctrine-migrations migrate
```### Swoole
To use swoole, just set `DOCKER_TARGET_APP=swoole` in .env and rebuild the application container.
## Documentations
Learn more at these links:
- [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/)
- [Doctrine reference](https://www.doctrine-project.org/projects/doctrine-bundle/en/latest/configuration.html)
- [Twig](https://twig.symfony.com/)
- [Swoole](https://openswoole.com/docs)