承接 smartgecko/governor-framework 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

smartgecko/governor-framework

Composer 安装命令:

composer require smartgecko/governor-framework

包简介

PHP Command-Query-Responsibility-Segregation framework.

README 文档

README

Build Status Scrutinizer Code Quality Code Coverage

Governor Framework is a Command and Query Responsibility Segregation library for PHP 5.5+.

It provides components to build applications following the CQRS patterns such as:

  • Command Handling
  • Event Handling
  • Event Sourcing
  • Event Stores
  • Sagas
  • Unit Of Work
  • Repositories
  • Serialization
  • AMQP support
  • Testing

The main source of inspiration for this library was the Axon Framework written in Java and the Governor Framework can be viewed as a PHP port of the Axon, because it retains its basic building blocks.

The library can be directly integrated into the Symfony 2 framework as a bundle. The core of the Symfony 2 integration was taken from the LiteCQRS framework.

Quick Start

The Domain Model

To demonstrate the features of the Governor Framework we will work with a rather simple User model. The User class is our aggregate root. Aggregate roots in Governor must either implement the Governor\Framework\Domain\AggregateRootInterface interface or extend one of the built in base classes:

  • Governor\Framework\Domain\AbstractAggregateRoot
  • Governor\Framework\EventSourcing\AbstractEventSourcedAggregateRoot
  • Governor\Framework\EventSourcing\Annotation\AbstractAnnotatedAggregateRoot

In this example we will use the aggregate root with annotation support. Our aggregate will also serve as a command handler in this example.

The aggregate will react to the commands

  • CreateUserCommand
  • ChangeUserEmailCommand

which will produce the corresponding events

  • UserCreatedEvent
  • UserEmailChangedEvent

Our aggregate root implementation will look the following.

class User extends AbstractAnnotatedAggregateRoot 
{  
    /**
     * @AggregateIdentifier
     * @var string
     */
    private $identifier;
    private $email;
    
    /**
     * @CommandHandler
     * @param CreateUserCommand $command
     */
    public function __construct(CreateUserCommand $command)
    {
        $this->apply(new UserCreatedEvent($command->getIdentifier(), $command->getEmail()));
    }

    /**
     * @CommandHandler
     * @param ChangeUserEmailCommand $command
     */
    public function changeEmail(ChangeUserEmailCommand $command)
    {
        $this->apply(new UserEmailChangedEvent($this->identifier, $command->getEmail()));
    }

    /**
     * @EventHandler
     * @param UserEmailChangedEvent $event
     */
    public function onEmailChanged(UserEmailChangedEvent $event)
    {
        $this->email = $event->getEmail();
    }

    /**
     * @EventHandler
     * @param UserCreatedEvent $event
     */
    public function onUserCreated(UserCreatedEvent $event)
    {
        $this->identifier = $event->getIdentifier();
        $this->email = $event->getEmail();
    }

    public function getEmail()
    {
        return $this->email;
    }

}

Commands and Events

We introduce 2 operations over the aggregate - one will create a new user and the second will change the user email. Notice the @Type annotations on the event class - Governor Framework uses the excellent JMS serializer library for serialization and deserialization purposes. To allow event deserialization when rebuilding the aggregate from an event stream the annotations must be present in order to successfully deserialize the events.

Our commands and events are implemented like this:

abstract class AbstractUserEvent
{

    /**
     * @Type("string")
     * @var string
     */
    private $identifier;

    /**
     * @Type("string")
     * @var string
     */
    private $email;

    function __construct($identifier, $email)
    {
        $this->identifier = $identifier;
        $this->email = $email;
    }

    public function getIdentifier()
    {
        return $this->identifier;
    }

    public function getEmail()
    {
        return $this->email;
    }

}

class UserCreatedEvent extends AbstractUserEvent
{
    
}

class UserEmailChangedEvent extends AbstractUserEvent
{
    
}

abstract class AbstractUserCommand
{
    /**
     * @TargetAggregateIdentifier
     * @var string 
     */
    private $identifier;
    private $email;

    function __construct($identifier, $email)
    {
        $this->identifier = $identifier;
        $this->email = $email;
    }

    public function getIdentifier()
    {
        return $this->identifier;
    }

    public function getEmail()
    {
        return $this->email;
    }

}

class CreateUserCommand extends AbstractUserCommand
{
    
}

class ChangeUserEmailCommand extends AbstractUserCommand
{
    
}

Event listeners

We can register event listeners to listen for events on the event bus. The event listeners need to implement the Governor\Framework\EventHandling\EventListenerInterface interface.

This simple listener that will listen for all events on the event bus and print their payload.

class UserEventListener implements EventListenerInterface
{

    public function handle(EventMessageInterface $event)
    {
        print_r($event->getPayload());
    }

}

Wrapping it all together

Now we can complete the example by setting up the necessary infrastructure in the following steps

  1. We need to set up a PSR-0 compatible logger like Monolog.
  2. Create a command bus and for convienience wrap it in a command gateway.
  3. Initialize an event store backed by a filesystem. Note that if you don't want to use event sourcing this step can be skipped.
  4. Set up a simple event bus
  5. Create an event sourcing repository
  6. Subscribe the annotated aggregate root to the command bus so it can recieve commands.
  7. Register an event listener that will display the content of our events.
  8. Dispatch commands.
// set up logging 
$logger = new Logger('governor');
$logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));

// 1. create a command bus and command gateway
$commandBus = new SimpleCommandBus();
$commandBus->setLogger($logger);
$commandGateway = new DefaultCommandGateway($commandBus);

$rootDirectory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'CommandHandlerExample';
@mkdir($rootDirectory);
echo sprintf("Initializing FileSystemEventStore in %s\n", $rootDirectory);

// 2. initialize the event store
$eventStore = new FilesystemEventStore(new SimpleEventFileResolver($rootDirectory),
    new JMSSerializer());

// 3. create the event bus
$eventBus = new SimpleEventBus();
$eventBus->setLogger($logger);

// 4. create an event sourcing repository
$repository = new EventSourcingRepository(User::class,
    $eventBus, new NullLockManager(), $eventStore,
    new GenericAggregateFactory(User::class));

//5. create and register our commands
AnnotatedAggregateCommandHandler::subscribe(User::class, $repository, $commandBus);

//6. create and register the eventlistener
$eventListener = new UserEventListener();
$eventBus->subscribe($eventListener);

//7. send commands 
$aggregateIdentifier = Uuid::uuid1()->toString();

$commandGateway->send(new CreateUserCommand($aggregateIdentifier,
    'email@davidkalosi.com'));
$commandGateway->send(new ChangeUserEmailCommand($aggregateIdentifier,
    'newemail@davidkalosi.com'));

Licensing

Governor Framework is licensed under the MIT license.

smartgecko/governor-framework 适用场景与选型建议

smartgecko/governor-framework 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 326 次下载、GitHub Stars 达 113, 最近一次更新时间为 2015 年 04 月 14 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 smartgecko/governor-framework 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 smartgecko/governor-framework 我们能提供哪些服务?
定制开发 / 二次开发

基于 smartgecko/governor-framework 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 326
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 113
  • 点击次数: 14
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 113
  • Watchers: 12
  • Forks: 12
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2015-04-14