think-codee/laravel-command-bus

v1.0.2 2024-06-11 12:34 UTC

This package is not auto-updated.

Last update: 2024-10-01 14:08:49 UTC


README

此包为在Laravel应用程序中实现命令模式提供了一种简单高效的方法,允许更好地分离关注点并使代码更易于维护。

安装

使用composer安装

composer require think-codee/laravel-command-bus

可选地,您可以使用以下命令发布配置文件:

php artisan vendor:publish --tag="command-bus-config"

以下为配置文件内容:

return [
    'buses' => [
        'default' => [
            'class' => \ThinkCodee\Laravel\CommandBus\Default\Bus::class,
            'interface' => \ThinkCodee\Laravel\CommandBus\Contracts\Bus::class,
            'alias' => 'bus.default',
            'middleware' => [],
            'handler_resolver' => \ThinkCodee\Laravel\CommandBus\Resolvers\SuffixHandlerResolver::class,
            'handler_method' => 'handle',
        ],
    ]
];

用法

此包允许您创建和管理多个命令总线,为Laravel应用程序中处理不同类型的命令提供了一个强大灵活的系统。特别适用于实现CQRS(命令和查询责任分离)等架构模式,该模式将读取和更新操作分离。每个总线都可以配置自己的中间件和处理器解析器,增强应用程序的模块化和组织。

定义总线

要创建一个总线,首先定义一个接口

use ThinkCodee\Laravel\CommandBus\Contracts\CommandBus;

interface QueryBusInterface extends CommandBus
{
}

然后,创建一个实现此接口的类

use ThinkCodee\Laravel\CommandBus\Bus;

class QueryBus extends Bus implements QueryBusInterface
{
}

您可以使用以下Artisan命令创建一个总线

php artisan command-bus:make:bus QueryBus

每个总线都必须在配置文件中进行注册。包将绑定接口到相应的类并分配一个别名

'query' => [
    'class' => \App\Buses\Query\QueryBus::class,
    'interface' => \App\Buses\Query\QueryBusInterface::class,
    'alias' => 'bus.query',
];

然后,您可以在应用程序中使用以下方式使用总线

use App\Buses\Query\QueryBusinterface; 

class Controller
{
    public function __construct(
        private QueryBusInterface $queryBus,
    ) {}

    public function show(int $id)
    {
        $users = $this->queryBus->handle(
            new GetUserQuery($id)
        );

        // Alternatively:
        // app('bus.query')->handle(
        //     new GetUsersQuery()  
        // );
    }
}

定义命令和处理程序

要定义一个命令

use ThinkCodee\Laravel\CommandBus\Contracts\Command;

class GetUserQuery implements Command
{
    public function __construct(public int $id) {}
}

要定义命令的处理程序

class GetUserQueryHandler
{
    public function handle(GetUserQuery $query)
    {
        // Handle the command, e.g., process $query->id
        // return User::findOrFail($query->id);
    }
}

您可以使用以下Artisan命令创建具有处理程序的命令

php artisan command-bus:make:command GetUserQuery

定义中间件

在此包中,中间件的工作方式与标准的Laravel中间件类似。它们允许在处理命令前后运行代码,为您的命令处理逻辑添加常见行为。

要定义一个中间件,创建一个在处理之前和/或之后处理命令的类

class LogExceptionsMiddleware
{
    public function handle(Command $command, Closure $next)
    {
        try {
            return $next($command);
        } catch (\Exception $e) {
            Log::error($e->getMessage());
            
            throw $e;
        }
    }
}

注册中间件

您可以使用属性将中间件注册到特定的命令处理程序

  • 使用#[Middleware]属性向处理程序添加中间件。
  • 属性的第二个参数是布尔值,true表示提前添加中间件,false(或省略)表示附加。
  • 使用#[ResetMiddleware]属性移除为该命令(在配置中注册)的所有现有中间件,并仅应用指定的中间件。
// This will prepend LogExceptionsMiddleware to the existing middleware
#[Middleware([LogExceptionsMiddleware::class], true)]
class StoreUserCommandHandler
{
    public function handle(StoreUserCommand $command): int
    {
        // Handle the command, e.g., process $command->email
        
        // $user = User::create(['email' => $command->email]);
        // return $user->id;
    }
}
// Handle the command with LogExceptionsMiddleware only
#[ResetMiddleware]
#[Middleware([LogExceptionsMiddleware::class])]
class StoreUserCommandHandler
{
    public function handle(StoreUserCommand $command): int
    {
        // Handle the command, e.g., process $command->email
        
        // $user = User::create(['email' => $command->email]);
        // return $user->id;
    }
}

您仍然可以在配置文件中注册中间件,将它们分配给特定的总线。中间件将应用于总线处理的所有命令。

'default' => [
    'class' => \ThinkCodee\Laravel\CommandBus\Default\Bus::class,
    'interface' => \ThinkCodee\Laravel\CommandBus\Contracts\Bus::class,
    'alias' => 'bus.default',
    'middleware' => [
        LogExceptionsMiddleware::class,
        //e.g. ExecuteWithinDatabaseTransaction
    ],
],

处理器解析器

每个总线都有一个处理器解析器,它确定如何为给定的命令解析合适的处理器。解析器和处理命令的方法在配置文件中为每个总线指定

'handler_resolver' => \ThinkCodee\Laravel\CommandBus\Resolvers\SuffixHandlerResolver::class,
'handler_method' => 'handle',

每个处理器解析器都必须实现HandlerResolver接口。《SuffixHandlerResolver》默认随包提供。如果您有一个名为TestCommand.php的命令,它将尝试将处理程序名称解析为同一目录下的TestCommandHandler.php

当命令通过解析的处理程序运行时,它将尝试使用配置文件中指定的方法。

为特定命令指定处理器

您还可以使用#[Handler]属性为命令设置特定的处理器。第二个参数是可选的,指定要使用的方法名称。如果没有指定,将使用配置文件中的方法名称。

#[Handler(StoreUserCustomHandler::class, 'customMethod')]
class StoreUserCommand
{
    // Command implementation
}

更新日志

请参阅变更日志获取关于最近更改的更多信息。

运行测试

要运行测试,请执行以下命令:

  composer test