cv65kr/messenger
Composer 安装命令:
composer require cv65kr/messenger
包简介
CQRS + Event Sourcing for Symfony.
README 文档
README
This is simple implementation CQRS + Event Sourcing for Symfony.
Installation
composer require cv65kr/messenger
Activate in config/bundles.php:
Messenger\MessengerBundle::class => ['all' => true],
Update database (migration in future):
bin/console d:s:u --force --dump-sql
To activate async bus, open config/packages/messenger.yaml and paste:
framework: messenger: transports: events: "%env(MESSENGER_TRANSPORT_DSN)%" routing: 'Messenger\Event\EventInterface': events
How to use
The current example: https://github.com/cv65kr/symfony-4-es-cqrs-boilerplate/tree/feature/es
Aggregate root
class User extends AggregateRoot { /** @var UuidInterface */ private $uuid; /** @var Email */ private $email; /** @var HashedPassword */ private $hashedPassword; /** @var DateTime */ private $createdAt; /** @var DateTime|null */ private $updatedAt; public static function create( UuidInterface $uuid, Credentials $credentials, UniqueEmailSpecificationInterface $uniqueEmailSpecification ): self { $uniqueEmailSpecification->isUnique($credentials->email); $user = new self(); $user->apply(new UserWasCreated($uuid, $credentials, DateTime::now())); return $user; } private function setEmail(Email $email): void { $this->email = $email; } private function setHashedPassword(HashedPassword $hashedPassword): void { $this->hashedPassword = $hashedPassword; } private function setCreatedAt(DateTime $createdAt): void { $this->createdAt = $createdAt; } private function setUpdatedAt(DateTime $updatedAt): void { $this->updatedAt = $updatedAt; } public function createdAt(): string { return $this->createdAt->toString(); } public function updatedAt(): ?string { return isset($this->updatedAt) ? $this->updatedAt->toString() : null; } public function email(): string { return $this->email->toString(); } public function uuid(): string { return $this->uuid->toString(); } public function getAggregateRootId(): AggregateRootId { return AggregateRootId::fromUUID($this->uuid); } protected function applyUserWasCreated(UserWasCreated $event): void { $this->uuid = $event->uuid; $this->setEmail($event->credentials->email); $this->setHashedPassword($event->credentials->password); $this->setCreatedAt($event->createdAt); } }
Event Sourcing Repository
final class UserStore extends EventSourcingRepository implements UserRepositoryInterface { public function store(User $user): void { $this->save($user); } public function get(UuidInterface $uuid): User { /** @var User $user */ $user = $this->load(AggregateRootId::fromUUID($uuid)); return $user; } public function getAggregateRoot(): string { return User::class; } }
Projection
Read model
class UserView implements ReadModelInterface { /** @var UuidInterface */ private $uuid; /** @var Credentials */ private $credentials; /** @var DateTime */ private $createdAt; /** @var DateTime */ private $updatedAt; public static function fromSerializable(EventInterface $event): self { return self::deserialize($event->serialize()); } public static function deserialize(array $data): self { $instance = new self(); $instance->uuid = Uuid::fromString($data['uuid']); $instance->credentials = new Credentials( Email::fromString($data['credentials']['email']), HashedPassword::fromHash($data['credentials']['password'] ?? '') ); $instance->createdAt = DateTime::fromString($data['created_at']); $instance->updatedAt = isset($data['updated_at']) ? DateTime::fromString($data['updated_at']) : null; return $instance; } public function serialize(): array { return [ 'uuid' => $this->getId(), 'credentials' => [ 'email' => (string) $this->credentials->email, ], ]; } public function uuid(): UuidInterface { return $this->uuid; } public function email(): string { return (string) $this->credentials->email; } public function changeEmail(Email $email): void { $this->credentials->email = $email; } public function changeUpdatedAt(DateTime $updatedAt): void { $this->updatedAt = $updatedAt; } public function hashedPassword(): string { return (string) $this->credentials->password; } public function getId(): string { return $this->uuid->toString(); } }
Projector
class UserProjectionFactory extends Projector { /** @var MysqlUserReadModelRepository */ private $repository; public function __construct(MysqlUserReadModelRepository $repository) { $this->repository = $repository; } protected function applyUserWasCreated(UserWasCreated $userWasCreated): void { $userReadModel = UserView::fromSerializable($userWasCreated); $this->repository->add($userReadModel); } protected function applyUserEmailChanged(UserEmailChanged $emailChanged): void { /** @var UserView $userReadModel */ $userReadModel = $this->repository->oneByUuid($emailChanged->uuid); $userReadModel->changeEmail($emailChanged->email); $userReadModel->changeUpdatedAt($emailChanged->updatedAt); $this->repository->apply(); } }
Consume events from queue
class SendEventsToElasticConsumer implements EventHandlerInterface { /** @var EventElasticRepository */ private $eventElasticRepository; public function __construct(EventElasticRepository $eventElasticRepository) { $this->eventElasticRepository = $eventElasticRepository; } public function __invoke(EventInterface $event): void { $this->eventElasticRepository->store($event); } }
cv65kr/messenger 适用场景与选型建议
cv65kr/messenger 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5 次下载、GitHub Stars 达 7, 最近一次更新时间为 2020 年 02 月 15 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 cv65kr/messenger 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 cv65kr/messenger 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 5
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 7
- 点击次数: 7
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2020-02-15