thepsion5/admiral

简单的PHP命令总线实现

dev-master 2014-07-24 15:44 UTC

This package is not auto-updated.

Last update: 2024-09-24 02:38:35 UTC


README

#Admiral Build Status Coverage Status 简单但灵活的PHP命令总线模式实现。##安装 将包添加到你的composer.json文件

{
    "require": {
        "thepsion5/admiral" : "dev-master"
    }
}

然后运行 composer update

##基本用法 在这个上下文中,命令是一个DTO,代表应用程序的单个高级指令。让我们考虑一个音乐播放列表管理应用程序。我们需要以下四个东西

  1. 一个实现 \Thepsion5\Admiral\CommandInterface 的命令类
  2. 一个实现 \Thepsion5\Admiral\CommandHandlerInterface 的处理类
  3. 一个创建命令实例并将其传递给命令总线的类

###创建一个命令

class AddAlbumToLibraryCommand implements \Thepsion5\Admiral\CommandInterface
{
    public $albumName;
    public $artistId;
    public $songs = [];

    public function __construct($artistId, $albumName, array $songs)
    {
        $this->artistId = $artistId;
        $this->albumName = $albumName;
        $this->songs = $songs;
    }
}

###创建相应的命令处理器

class AddAlbumToLibraryCommandHandler implements \Thepsion5\Admiral\CommandHandlerInterface
{
    public function handle(AddAlbumToLibraryCommand $command)
    {
        //perform business logic here
    }
}

###执行命令

class AdminController
{
    public function __construct()
    {
        $this->commandBus = \Thepsion5\Admiral\CommandBusFactory::makeCommandBus();
    }

    function postUploadAlbum($artistId)
    {
        $input = $this->input->post();
        $command = new AddAlbumToLibraryCommand($artistId, $input['title'], $input['songs']);
        $this->commandBus->execute($command);
    }
}

命令总线将自动尝试将命令类的名称解析为处理器,通过将 'Command' 替换为 'CommandHandler'。因此,Acme\Domain\Albums\AddAlbumToLibraryCommand 将被转换为 Acme\Domain\Albums\AddAlbumToLibraryCommandHandler。接下来,命令总线将创建处理器并返回 handle 函数的结果。

##高级用法

###手动注册命令处理器 如果你为命令和处理器有不同的命名约定,你可以手动注册处理器

$resolver = $commandBus->getResolver();
$resolver->register('Acme\Commands\AddAlbumToLibrary', 'Acme\Handlers\AddAlbumToLibrary');

你也可以通过实现 Thepsion5\Admiral\CommandHandlerResolverInterface 并手动设置它来使用自定义解析器

$resolver = new AcmeCommandHandlerResolver();
$commandBus->setResolver($resolver);

###处理器中的依赖注入 对于具有外部依赖的处理器,Admiral 支持使用 illuminate/container 进行依赖注入,这是 Laravel 框架背后的 DI 容器。它可以通过命令处理器的 getContainer() 方法访问

$container = $commandBus->getResolver()->getContainer();

容器实现了 Thepsion5\Admiral\Container\ContainerInterface。绑定可以配置如下

$container->bind(
    'Acme\Domain\Albums\AlbumRepositoryInterface',
    '\Acme\Infrastructure\Albums\DbAlbumRepository'
);
//returns an instance of DbAlbumRepository
$repository = $container->make('Acme\Domain\Albums\AlbumRepositoryInterface');

###使用其他 DI 容器

你可以通过创建一个实现 ContainerInterface 的适配器来使用自定义 DI 容器

$commandBus->getResolver()->setContainer(new SymfonyDiContainer);

##访问控制

可以向命令总线添加额外的 ACL 功能,以提供对谁能够执行命令的细粒度控制,而无需将此功能添加到命令处理器中。

要使用此功能,我们需要使用两个附加组件

  1. 一个 AccessControlCommandBus 实例
  2. 一个 AccessPolicy

###创建命令总线访问策略类

可以使用工厂实例化 AccessControlCommandBus

$commandBus = \Thepsion5\Admiral\CommandBusFactory::makeAccessControlCommandBus();

此实例与标准命令总线的工作方式相同,但允许使用访问策略类。用于解析它的方法与用于解析命令处理器的类似。例如,CreateAlbumCommand 将在同一命名空间中查找 CreateAlbumAccessPolicy

以下是一个示例访问策略类

class CreateAlbumAccessPolicy implements \Thepsion5\Admiral\AccessControl\AccessPolicyInterface
{
    public function assess(CommandInterface $command)
    {
        if(!Auth::user()) {
            throw new AccessControlException("You must be logged in to create an album.");
        } elseif(!Auth::user()->owns($command->artistId)) {
            throw new AccessControlException("You can only create Album for an artist you own.");
        }
    }
}

如果没有找到匹配的类,它将被忽略,并将正常调用处理器类。

##待办事项

  • 关于访问控制的更多文档