thepsion5 / admiral
简单的PHP命令总线实现
Requires
- php: >=5.4.0
- illuminate/container: 4.2.*
Requires (Dev)
- phpunit/phpunit: 4.0.*
- satooshi/php-coveralls: dev-master
This package is not auto-updated.
Last update: 2024-09-24 02:38:35 UTC
README
#Admiral
简单但灵活的PHP命令总线模式实现。##安装 将包添加到你的composer.json文件
{ "require": { "thepsion5/admiral" : "dev-master" } }
然后运行 composer update
##基本用法 在这个上下文中,命令是一个DTO,代表应用程序的单个高级指令。让我们考虑一个音乐播放列表管理应用程序。我们需要以下四个东西
- 一个实现
\Thepsion5\Admiral\CommandInterface
的命令类 - 一个实现
\Thepsion5\Admiral\CommandHandlerInterface
的处理类 - 一个创建命令实例并将其传递给命令总线的类
###创建一个命令
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 功能,以提供对谁能够执行命令的细粒度控制,而无需将此功能添加到命令处理器中。
要使用此功能,我们需要使用两个附加组件
- 一个
AccessControlCommandBus
实例 - 一个
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."); } } }
如果没有找到匹配的类,它将被忽略,并将正常调用处理器类。
##待办事项
- 关于访问控制的更多文档