robiningelbrecht/php-slim-skeleton

dev-master 2023-08-29 13:12 UTC

This package is auto-updated.

Last update: 2024-08-29 15:15:57 UTC


README

Slim

CI Codecov.io License PHPStan Enabled PHP

使用 AMQP 和 CQRS 的事件驱动 Slim 4 框架骨架

安装

默认安装配置

默认安装配置没有示例。如果您对此有所了解,并希望从头开始,应使用此配置。

> 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

完整安装配置

完整安装配置包含一个完整的工作示例。

> 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

一些示例

注册新路由

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;
    }
}

转到 config/routes.php 并为您的 RequestHandler 添加路由

return function (App $app) {
    // Set default route strategy.
    $routeCollector = $app->getRouteCollector();
    $routeCollector->setDefaultInvocationStrategy(new RequestResponseArgs());
    
    $app->get('/user/overview', UserOverviewRequestHandler::class.':handle');
};

完整文档

控制台命令

控制台应用程序使用 Symfony 控制台组件来利用 CLI 功能。

#[AsCommand(name: 'app:user:create')]
class CreateUserConsoleCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // ...
        return Command::SUCCESS;
    }
}

完整文档

域命令和命令处理器

该骨架允许您使用命令和命令处理器来执行操作。这两个总是成对出现,当在写入模型中创建新命令时,必须同时创建相应的命令处理器。

创建新命令

namespace App\Domain\WriteModel\User\CreateUser;

class CreateUser extends DomainCommand
{
 
}

创建相应的命令处理器

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.
    }
}

完整文档

事件驱动

该项目的主旨在于一切或可以成为事件驱动的。默认情况下不提供事件源。

创建新事件

class UserWasCreated extends DomainEvent
{
    public function __construct(
        private UserId $userId,
    ) {
    }

    public function getUserId(): UserId
    {
        return $this->userId;
    }
}

记录事件

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;
    }
}

发布事件

class UserRepository extends DbalAggregateRootRepository
{
    public function add(User $user): void
    {
        $this->connection->insert(/*...*/);
        $this->publishEvents($user->getRecordedEvents());
    }
}

监听事件

#[AsEventListener(type: EventListenerType::PROCESS_MANAGER)]
class UserNotificationManager extends ConventionBasedEventListener
{
   
    public function reactToUserWasCreated(UserWasCreated $event): void
    {
        // Send out some notifications.
    }
}

完整文档

使用 RabbitMQ 异步处理命令

该项目选择的 AMQP 实现是 RabbitMQ,但它可以轻松切换到例如亚马逊的 AMQP 解决方案。

注册新队列

#[AsEventListener(type: EventListenerType::PROCESS_MANAGER)]
class UserCommandQueue extends CommandQueue
{
}

排队命令

class YourService
{
    public function __construct(
        private readonly UserCommandQueue $userCommandQueue
    ) {
    }

    public function aMethod(): void
    {
        $this->userCommandQueue->queue(new CreateUser(/*...*/));
    }
}

消费队列

> docker-compose run --rm php-cli bin/console app:amqp:consume user-command-queue

完整文档

数据库迁移

为了管理数据库迁移,使用了 doctrine/migrations 包。

#[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,
    ) {
    }

    // ...
}

您可以使用 Doctrine 通过比较您的数据库模式当前状态与使用 ORM 定义的映射信息来为您生成迁移,然后执行该迁移。

> docker-compose run --rm php-cli vendor/bin/doctrine-migrations diff
> docker-compose run --rm php-cli vendor/bin/doctrine-migrations migrate

完整文档

模板引擎

该项目选择的模板引擎是 Twig,可用于渲染任何 HTML 相关的内容。

创建模板

<h1>Users</h1>
<ul>
    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% endfor %}
</ul>

渲染模板

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;
    }
}

完整文档

文档

在这些链接中了解更多信息

使用此骨架的项目

贡献

请参阅 CONTRIBUTING 了解详细信息。