{"id":18040500,"url":"https://github.com/mrhdolek/slim4-boirlerplate","last_synced_at":"2026-05-02T06:43:43.343Z","repository":{"id":169771360,"uuid":"645821303","full_name":"MrHDOLEK/slim4-boirlerplate","owner":"MrHDOLEK","description":"Template for a project based on the slim framework","archived":false,"fork":false,"pushed_at":"2025-04-01T07:10:25.000Z","size":394,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-05T01:42:52.601Z","etag":null,"topics":["amqp","ddd","doctrine","hactoberfest","hactoberfest-accepted","hactoberfest2023","microservices","phpunit","rabbitmq","slim","slim4","slim4-doctrine","slim4-framework","slim4-skeleton","swoole"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MrHDOLEK.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-26T14:08:20.000Z","updated_at":"2025-02-11T08:56:54.000Z","dependencies_parsed_at":"2023-11-25T12:23:44.054Z","dependency_job_id":"2c57d97d-42f4-4b84-9639-9c7cddd1c926","html_url":"https://github.com/MrHDOLEK/slim4-boirlerplate","commit_stats":null,"previous_names":["mrhdolek/slim4-template","mrhdolek/slim4-boirlerplate"],"tags_count":7,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrHDOLEK%2Fslim4-boirlerplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrHDOLEK%2Fslim4-boirlerplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrHDOLEK%2Fslim4-boirlerplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrHDOLEK%2Fslim4-boirlerplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MrHDOLEK","download_url":"https://codeload.github.com/MrHDOLEK/slim4-boirlerplate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276097,"owners_count":20912287,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amqp","ddd","doctrine","hactoberfest","hactoberfest-accepted","hactoberfest2023","microservices","phpunit","rabbitmq","slim","slim4","slim4-doctrine","slim4-framework","slim4-skeleton","swoole"],"created_at":"2024-10-30T15:06:15.931Z","updated_at":"2026-05-02T06:43:43.336Z","avatar_url":"https://github.com/MrHDOLEK.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Slim 4 Framework skeleton\n\n![Slim](slim.webp)\n\n[![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)\n[![Codecov.io](https://codecov.io/gh/MrHDOLEK/slim4-boirlerplate/graph/badge.svg?token=KKBMW5HJVM)](https://codecov.io/gh/MrHDOLEK/slim4-boirlerplate)\n[![License](https://img.shields.io/github/license/robiningelbrecht/slim-skeleton-ddd-amqp?color=428f7e\u0026logo=open%20source%20initiative\u0026logoColor=white)](https://github.com/MrHDOLEK/slim4-boirlerplate/blob/master/LICENSE)\n[![PHPStan Enabled](https://img.shields.io/badge/PHPStan-level%205-succes.svg?logo=php\u0026logoColor=white\u0026color=31C652)](https://phpstan.org/)\n[![PHP](https://img.shields.io/packagist/php-v/mrhdolek/slim4-boirlerplate/dev-main?color=%23777bb3\u0026logo=php\u0026logoColor=white)](https://php.net/)\n\n\n---\n#### An Slim 4 Framework skeleton using AMQP and DDD\n\nI was inspired to create this skeleton from: [robiningelbrecht](https://github.com/robiningelbrecht).\n\n## Project setup\n\n### Development\nIf you have problems with permissions please add sudo before make example:\n- `sudo make install`\n- `sudo make start`\n### Run env for Mac/Linux\n\n- `make install`\n- `make start`\n- `make db-create`\n\n### Run env for Windows\nPlease install packages makefile for [Windows](http://gnuwin32.sourceforge.net/packages/make.htm)\n- `make install`\n- `make start`\n- `make db-create`\n\n### Address where the environment is available\n- `http://localhost`\n## Documentation for a Rest Api\n- `http://localhost/docs/v1`\n## RabbitMq dashboard\n- `http://localhost:15672`\n## All commands\n\n-  `make help`\n\n## Some examples\n\n### Registering a new route\n\n```php\nnamespace App\\Application\\Actions\\User;\n\nclass GetAllUsersAction extends UserAction\n{\n    public function __construct(\n        private readonly UserService $userService,\n        protected LoggerInterface $logger,\n    ) {\n        parent::__construct($logger);\n    }\n\n    protected function action(): Response\n    {\n        $user = $this-\u003euserService-\u003egetAllUsers();\n\n        return $this-\u003erespondWithJson(new UsersResponseDto($user));\n    }\n}\n```\n\nHead over to `config/routes.php` and add a route for your RequestHandler:\n\n```php\nreturn function (App $app) {\n        $group-\u003eget(\"/users\", GetAllUsersAction::class)\n            -\u003esetName(\"getAllUsers\");\n};\n```\n\n### Console commands\n\nThe console application uses the Symfony console component to leverage CLI functionality.\n\n\n```php\n#[AsCommand(name: 'app:user:create')]\nclass CreateUserConsoleCommand extends Command\n{\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        // ...\n        return Command::SUCCESS;\n    }\n}\n```\n\n### Scheduling Commands\n\nTo 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:\n\n```php\n$scheduler = new GO\\Scheduler();\n$scheduler-\u003ephp('/path/to/command app:user:create')-\u003edaily();\n$scheduler-\u003erun();\n```\nIn this example, the app:user:create command is scheduled to run every day.\n\n#### Running the Scheduler\nThe 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.\n\nFor instance, a cron job running every minute might look like this:\n\n```bash\n* * * * * ./bin/console.php schedule\n```\n\nThis setup ensures that your scheduled commands are executed reliably and on time.\n\n\n### Domain event and event handlers\n\nThe framework implements the amqp protocol with handlers that allow events to be easily pushed onto the queue.\nEach event must have a handler implemented that consumes the event.\n\n#### Creating a new event\n\n```php\nclass UserWasCreated extends DomainEvent\n{\n \n}\n```\n\n#### Creating the corresponding event handler\n\n```php\nnamespace App\\Domain\\Entity\\User\\DomainEvents;\n\n#[AsEventHandler]\nclass UserWasCreatedEventHandler implements EventHandler\n{\n    public function __construct(\n    ) {\n    }\n\n    public function handle(DomainEvent $event): void\n    {\n        assert($event instanceof UserWasCreated);\n\n        // Do stuff.\n    }\n}\n```\n\n### Eventing\n\n#### Create a new event\n\n```php\nclass UserWasCreated extends DomainEvent\n{\n    public function __construct(\n        private UserId $userId,\n    ) {\n    }\n\n    public function getUserId(): UserId\n    {\n        return $this-\u003euserId;\n    }\n}\n```\n\n### Async processing of commands with RabbitMQ\n\nThe chosen AMQP implementation for this project is RabbitMQ, but it can be easily switched to for example Amazon's AMQP solution.\n\n#### Registering new queues\n\n```php\n#[AsAmqpQueue(name: \"user-command-queue\", numberOfWorkers: 1)]\nclass UserEventQueue extends EventQueue\n{\n}\n```\n\n#### Queueing events\n\n```php\nfinal readonly class UserEventsService\n{\n    public function __construct(\n        private UserEventQueue $userEventQueue,\n    ) {}\n\n    public function userWasCreated(User $user): void\n    {\n        $this-\u003euserEventQueue-\u003equeue(new UserWasCreated($user));\n    }\n}\n```\n\n#### Consuming your queue\n\n```bash\n\u003e docker-compose run --rm php bin/console.php app:amqp:consume user-command-queue\n```\n\n### Create new entity\n\nIf 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 . \nIt must be named so as to indicate where exactly the entity to be mapped is located.\n\n### Binding of interfaces/Registry global objects\n\nTo register a dependency or create a single configured global instance, you need to go to config/container.php\n\n### Mapping database data to custom objects\n\nTo map data from a database to a custom object you need to extend something from Doctrine/DBAL/Types .\n\n```php\nuse App\\Domain\\ValueObject\\UserType;\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Doctrine\\DBAL\\Types\\StringType;\n\nclass UserTypeType extends StringType\n{\n    const TYPE_NAME = 'UserType';\n\n    public function convertToPHPValue($value, AbstractPlatform $platform): ?UserType\n    {\n        return null !== $value ? UserType::fromString($value) : null;\n    }\n\n    public function getName()\n    {\n        return self::TYPE_NAME;\n    }\n}\n```\n\nAfter extending, you need to add a note in the xml that you are mapping a field to an object.\n\n```xml\n    \u003cfield name=\"type\" type=\"UserType\" column=\"type\" nullable=\"true\"/\u003e\n```\n\nFinally, you must add the new type in config/container.php where doctrine is configured\n\n```php\nuse Doctrine\\DBAL\\Connection;\nuse Doctrine\\DBAL\\DriverManager;\nuse Doctrine\\DBAL\\Types\\Type;\nuse Doctrine\\ORM\\EntityManager;\nuse Doctrine\\ORM\\EntityManagerInterface;\nuse Doctrine\\ORM\\Tools\\Setup;\n\nreturn [\n...\n    EntityManager::class =\u003e function (Settings $settings): EntityManager {\n        $config = Setup::createXMLMetadataConfiguration(\n            $settings-\u003eget(\"doctrine.metadata_dirs\"),\n            $settings-\u003eget(\"doctrine.dev_mode\"),\n        );\n        if (!Type::hasType('UserType')) {\n          Type::addType('UserType', UserTypeType::class);\n        }\n        return EntityManager::create($settings-\u003eget(\"doctrine.connection\"), $config);\n    },\n ...\n];\n\n```\n\n\n### Database migrations\n\nTo manage database migrations, the doctrine/migrations package is used.\n\n```xml\n\u003cdoctrine-mapping\nxmlns=\"http://doctrine-project.org/schemas/orm/doctrine-mapping\"\nxmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\nxsi:schemaLocation=\"http://doctrine-project.org/schemas/orm/doctrine-mapping\nhttps://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd\"\u003e\n\u003centity name=\"App\\Domain\\Entity\\User\\User\" table=\"users\"\u003e\n\u003cid name=\"id\" type=\"integer\" column=\"id\"\u003e\n\u003cgenerator strategy=\"SEQUENCE\"/\u003e\n\u003csequence-generator sequence-name=\"user_id_seq\" allocation-size=\"1\" initial-value=\"1\"/\u003e\n\u003c/id\u003e\n\u003cfield name=\"username\" type=\"string\" column=\"name\" length=\"64\" nullable=\"true\"/\u003e\n\u003cfield name=\"firstName\" type=\"string\" column=\"surname\" length=\"64\" nullable=\"true\"/\u003e\n\u003cfield name=\"lastName\" type=\"string\" column=\"email\" length=\"64\" nullable=\"true\"/\u003e\n\u003coptions\u003e\n\u003coption name=\"collate\"\u003eutf8mb4_polish_ci\u003c/option\u003e\n\u003c/options\u003e\n\u003c/entity\u003e\n\u003c/doctrine-mapping\u003e\n```\n\nThe mapping is done using a yaml which maps your entities from the domain to a structure in the database . \nIf you change something in yaml, you can use the commands below to generate a migration based on the difference.\n\n```bash\n\u003e docker-compose run --rm php vendor/bin/doctrine-migrations diff\n\u003e docker-compose run --rm php vendor/bin/doctrine-migrations migrate\n```\n\n## Documentations\n\nLearn more at these links:\n\n- [Slim framework](https://www.slimframework.com)\n- [PHP-DI](https://php-di.org/)\n- [Symfony Console Commands](https://symfony.com/doc/current/console.html)\n- [Doctrine migrations](https://www.doctrine-project.org/projects/doctrine-migrations/en/3.6/)\n- [Doctrine reference](https://www.doctrine-project.org/projects/doctrine-bundle/en/latest/configuration.html)\n- [Twig](https://twig.symfony.com/)\n- [Symfony Serializer](https://symfony.com/doc/current/serializer.html)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrhdolek%2Fslim4-boirlerplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrhdolek%2Fslim4-boirlerplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrhdolek%2Fslim4-boirlerplate/lists"}