Laravel¿ª·¢£ºÔõÑùʹÓÃLaravel Event Sourcing¹¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò£¿
laravel¿ª·¢£ºÔõÑùʹÓÃlaravel event sourcing¹¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò£¿
ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐòÊÇÒ»ÖÖʹÓÃÊÂÎñºÍÊÂÎñ´¦Öóͷ£Æ÷£¨Event Handler£©À´ÊµÏÖµÄÓ¦ÓóÌÐò¡£ÊÂÎñÇý¶¯µÄ¼Ü¹¹Ê¹µÃÓ¦ÓóÌÐòÔ½·¢ÈÝÒ×À©Õ¹ºÍά»¤£¬²¢ÇÒÔ½·¢ÎÞа£¬ÔÚÃæÁÙת±äʱԽ·¢ÈÝÒ×˳Ӧ¡£
LaravelÊÇÒ»ÖÖÊ¢ÐеÄPHP¿ò¼Ü£¬ËüÌṩÁËÒ»ÖÖ½Ð×öEvent SourcingµÄ¹¦Ð§£¬¿ÉÒÔ×ÊÖúÎÒÃǹ¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò¡£±¾ÎĽ«ÏÈÈÝÔõÑùʹÓÃLaravel Event Sourcing¹¹½¨Ò»¸ö¼òÆÓµÄÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò¡£
1.ʲôÊÇLaravel Event Sourcing£¿
Laravel Event SourcingÊÇÒ»ÖÖÊÂÎñÇý¶¯µÄ½¨Ä£¿ò¼Ü£¬ËüÊÇÓÉLaravelÌṩµÄÒ»¸öÌ×¼þ£¬ÓÃÓÚ×ÊÖúÎÒÃǹ¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò¡£Ëü¶ÔÊÂÎñ¾ÙÐд洢ºÍ»Ö¸´£¬Ê¹ÎÒÃÇÄܹ»ÖØÏÖÓ¦ÓóÌÐòÖеÄ״̬£¬²¢ÇÒÄܹ»»ØËݵ½Ö®Ç°µÄ״̬¡£
2.ΪʲôʹÓÃLaravel Event Sourcing£¿
ʹÓÃLaravel Event SourcingµÄÀûÒæÊÇ¿ÉÒÔÌá¸ßÓ¦ÓóÌÐòµÄ¿ÉÀ©Õ¹ÐԺͿÉά»¤ÐÔ¡£µ±ÎÒÃÇʹÓÃÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐòʱ£¬¸üÈÝÒ×Ã÷È·ºÍÐÞ¸ÄÓ¦ÓóÌÐòµÄ²î±ð²¿·Ö£¬²¢ÇÒÓ¦ÓóÌÐòÔ½·¢½áʵ¡£
ʹÓÃLaravel Event Sourcing£¬ÎÒÃÇ¿ÉÒÔÇáËÉʵÏÖ¶àÖÖģʽ£¬°üÀ¨CQRS£¨Command Query Responsibility Segregation£©Ä£Ê½ºÍES£¨Event Sourcing£©Ä£Ê½¡£
3.ÔõÑùʹÓÃLaravel Event Sourcing¹¹½¨Ò»¸öÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò£¿
ÔÚÕâ¸öÀý×ÓÖУ¬ÎÒÃǽ«¹¹½¨Ò»¸ö¼òÆÓµÄʹÃüÖÎÀíÓ¦ÓóÌÐò£¬Óû§¿ÉÒÔ½¨ÉèºÍÍê³ÉʹÃü¡£
°ì·¨Ò»£º½¨ÉèʹÃü
ÎÒÃÇ¿ÉÒÔͨ¹ý½¨ÉèʹÃüÀ´ÑÝʾÔõÑùʹÓÃLaravel Event Sourcing¡£Ê×ÏÈ£¬ÎÒÃÇÐèÒª½¨ÉèÒ»¸ö¡°TaskCreated¡±ÊÂÎñÀ´´¦Öóͷ£½¨ÉèʹÃüµÄÐÐΪ¡£
php artisan make:event TaskCreated
µÇ¼ºó¸´ÖÆ
°ì·¨¶þ£ºÎªÊ¹Ãü½¨ÉèÊÂÎñ´¦Öóͷ£Æ÷
Ò»µ©ÎÒÃǽ¨ÉèÁËÒ»¸öÊÂÎñ£¬ÎÒÃǾÍÐèÒª½¨ÉèÒ»¸öÊÂÎñ´¦Öóͷ£Æ÷À´´¦Öóͷ£Õâ¸öÊÂÎñ¡£ÏÖÔÚÎÒÃÇÐèÒª½¨ÉèÒ»¸öÊÂÎñ´¦Öóͷ£Æ÷À´´¦Öóͷ£¡°TaskCreated¡±ÊÂÎñ¡£
php artisan make:listener CreateTaskListener --event=TaskCreated
µÇ¼ºó¸´ÖÆ
°ì·¨Èý£º½«ÊÂÎñºÍÊÂÎñ´¦Öóͷ£Æ÷°ó¶¨ÔÚÒ»Æð
ÏÖÔÚÎÒÃÇÒª½«ÊÂÎñºÍÊÂÎñ´¦Öóͷ£Æ÷°ó¶¨ÔÚÒ»Æð¡£ÎÒÃÇ¿ÉÒÔÔÚLaravelµÄEventServiceProviderÎļþÖÐʵÏÖÕâÒ»µã¡£
protected $listen = [ TaskCreated::class => [ CreateTaskListener::class, ], ];
µÇ¼ºó¸´ÖÆ
°ì·¨ËÄ£ºÊ¹ÓÃÊÂÎñ´¦Öóͷ£Æ÷À´´¦Öóͷ£Ê¹Ãü½¨ÉèÊÂÎñ
ÏÖÔÚÎÒÃÇ¿ÉÒÔʹÓÃ×ðÁú¿Ê±ÊƼþ´¦Öóͷ£Æ÷À´´¦Öóͷ£Ê¹Ãü½¨ÉèÊÂÎñ¡£ÎÒÃÇҪʵÏֵĵÚÒ»¸öÊÂÎñ´¦Öóͷ£Æ÷ÊÇCreateTaskListener£¬Ëü½«ÏÖʵ½¨ÉèÐÂʹÃü¡£
public function handle(TaskCreated $event) { $task = new Task; $task->name = $event->name; $task->save(); }
µÇ¼ºó¸´ÖÆ
°ì·¨Î壺ʹÓÃLaravel Event SourcingÀ´´æ´¢ÊÂÎñ
ʹÓÃLaravel Event Sourcing¿ÉÒÔÈÃÎÒÃÇ´æ´¢ºÍ»Ö¸´ÊÂÎñ¡£ÎÒÃÇÐèÒªÔÚLaravelÖÐʹÓÃEvent Sourcing¿â£¬ºÃ±ÈBroadway¿â¡£
ÎÒÃÇ¿ÉÒÔʹÓÃLaravelµÄcomposer.jsonÎļþÀ´Ìí¼ÓBroadway¿â£º
"require": { "broadway/broadway": "^1.0", "broadway/serializer": "^1.0", "broadway/event-store": "^1.0" }
µÇ¼ºó¸´ÖÆ
È»ºóÔËÐÐÒÔÏÂÏÂÁî×°ÖÃBroadway¿â£º
composer install
µÇ¼ºó¸´ÖÆ
°ì·¨Áù£ºÊ¹ÓÃLaravel Event Sourcing
ÏÖÔÚÎÒÃÇ¿ÉÒÔʹÓÃLaravel Event SourcingÀ´´æ´¢ÊÂÎñ¡£
ÎÒÃÇÐèÒª½¨ÉèÒ»¸öÊÂÎñ´æ´¢Æ÷£¬À´´æ´¢ºÍ¼ìË÷ÊÂÎñ¡£ÎÒÃÇ¿ÉÒÔÔÚLaravelµÄappÎļþ¼ÐÖн¨ÉèÒ»¸öÃûΪTaskEventStore.phpµÄÀàÀ´ÊµÏÖËü£º
use BroadwayEventStoreEventStore; use BroadwayEventSourcingEventSourcingRepository; class TaskEventStore extends EventSourcingRepository { public function __construct(EventStore $eventStore) { parent::__construct( $eventStore, new TaskAggregateRootEventSourcedFactory(), new TaskAggregateRootEventSourcedRepository() ); } }
µÇ¼ºó¸´ÖÆ
ÎÒÃÇÐèÒªÔÚTaskEventStoreÀàµÄ½á¹¹º¯ÊýÖн¨ÉèÒ»¸öеÄÊÂÎñ´æ´¢¿â£¬²¢Ê¹ÓÃBroadway¿âÖеÄEventSourcingRepositoryÀ´´æ´¢ÊÂÎñ¡£ÎÒÃÇ»¹ÐèÒª½ç˵һ¸ö¾ÛºÏ¸ù¹¤³§ºÍ¾ÛºÏ¸ù´æ´¢¿âÀ´ÖÎÀí×ðÁú¿Ê±¾ÛºÏ¸ù¡£
ÏÖÔÚÎÒÃÇ¿ÉÒÔʹÓÃTaskEventStoreÀàÀ´´æ´¢ÊÂÎñ¡£ÎÒÃÇ¿ÉÒÔÔÚCreateTaskListenerÊÂÎñ´¦Öóͷ£Æ÷ÖÐÌí¼ÓÒÔÏ´úÂ룺
$eventStore = $this->app->make(TaskEventStore::class); $eventStream = new DomainEventStream([$event]); $aggregateRoot = $eventStore->load($command->taskId); $aggregateRoot->handle($event); $eventStore->save( $aggregateRoot->getUncommittedEvents(), $aggregateRoot->getId() );
µÇ¼ºó¸´ÖÆ
Õâ¸ö´úÂë¶Î»ñÈ¡TaskEventStoreÀàµÄʵÀý£¬½¨ÉèÒ»¸öÊÂÎñÁ÷£¬¼ÓÔؾۺϸù£¬Å²ÓÃhandleÒªÁì²¢ÉúÑÄδÌá½»µÄÊÂÎñ¡£
ÎÒÃÇÒ²ÐèÒªÔÚLaravelµÄServiceProviderÀàÖаó¶¨TaskEventStoreÀࣺ
$this->app->singleton(TaskEventStore::class, function ($app) { $eventStore = new InMemoryEventStore; return new TaskEventStore($eventStore); });
µÇ¼ºó¸´ÖÆ
°ì·¨Æߣº²éÕÒºÍÏÔʾʹÃü
ÏÖÔÚÎÒÃǽ¨ÉèÁËÒ»¸öеÄʹÃü£¬ÎÒÃÇ¿ÉÒÔͨ¹ýÐÞ¸Ä×ðÁú¿Ê±ÅÌÎÊÀ´ÏòÓû§ÏÔʾËùÓеÄʹÃü¡£
½¨ÉèÒ»¸öÃûΪShowTasksµÄÏÂÁ
php artisan make:command ShowTasks
µÇ¼ºó¸´ÖÆ
ÎÒÃÇҪʵÏֵĵÚÒ»¸öÏÂÁî´¦Öóͷ£Æ÷ÊÇShowTasks£¬Ëü½«·µ»ØËùÓÐʹÃü£¬ÒÔ±ãÁбíÏÔʾ¡£
public function handle() { $tasks = Task::all(); foreach ($tasks as $task) { $this->info("Name: {$task->name}"); } }
µÇ¼ºó¸´ÖÆ
°ì·¨°Ë£º±ê¼ÇʹÃüΪÒÑÍê³É
ÏÖÔÚÎÒÃÇҪģÄâ±ê¼ÇʹÃüΪÒÑÍê³ÉµÄÐÐΪ¡£ÎÒÃÇ¿ÉÒÔʹÓÃÒ»¸ö¡°TaskCompleted¡±ÊÂÎñÀ´¸ú×ÙÕâ¸öÐÐΪ¡£
Ê×ÏÈ£¬ÎÒÃÇÐèÒª½¨ÉèÒ»¸ö¡°TaskCompleted¡±ÊÂÎñ£º
php artisan make:event TaskCompleted
µÇ¼ºó¸´ÖÆ
È»ºó£¬ÎÒÃǽ«½¨ÉèÒ»¸öÃûΪCompleteTaskHandlerµÄÊÂÎñ´¦Öóͷ£Æ÷À´´¦Öóͷ£Õâ¸öÊÂÎñ¡£
php artisan make:listener CompleteTaskHandler --event=TaskCompleted
µÇ¼ºó¸´ÖÆ
½ÓÏÂÀ´£¬ÎÒÃǰ󶨡°TaskCompleted¡±ÊÂÎñºÍCompleteTaskHandlerÊÂÎñ´¦Öóͷ£Æ÷£º
protected $listen = [ TaskCreated::class => [ CreateTaskListener::class, ], TaskCompleted::class => [ CompleteTaskHandler::class, ], ];
µÇ¼ºó¸´ÖÆ
×îºó£¬ÎÒÃÇҪʵÏֵĵڶþ¸öÊÂÎñ´¦Öóͷ£Æ÷ÊÇCompleteTaskHandler£¬Ëü½«ÉèÖÃʹÃü״̬ΪÒÑÍê³É¡£
public function handle(TaskCompleted $event) { $task = Task::where('name', $event->name)->firstOrFail(); $task->completed = true; $task->save(); }
µÇ¼ºó¸´ÖÆ
ÖÁ´Ë£¬ÎÒÃÇÀֳɵؽ¨ÉèÁËÒ»¸öÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò£¬Óû§¿ÉÒÔ½¨Éè¡¢Íê³ÉºÍÏÔʾʹÃüÁÐ±í¡£
½áÂÛ
ʹÓÃLaravel Event Sourcing¿ÉÒÔ×ÊÖúÎÒÃǹ¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò¡£ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò¾ßÓиü¸ßµÄ¿ÉÀ©Õ¹ÐԺͿÉά»¤ÐÔ£¬²¢ÇÒÔ½·¢ÎÞа¡£Í¨¹ýLaravel Event Sourcing£¬ÎÒÃÇ¿ÉÒÔÇáËɵØʵÏÖ¶àÖÖģʽ£¬°üÀ¨CQRSºÍESģʽ£¬Òò´ËÎÒÃǽ¨Ò鿪·¢Ö°Ô±ÔÚ¹¹½¨Ó¦ÓóÌÐòʱʹÓÃÊÂÎñÇý¶¯µÄ¼Ü¹¹¡£
ÒÔÉϾÍÊÇLaravel¿ª·¢£ºÔõÑùʹÓÃLaravel Event Sourcing¹¹½¨ÊÂÎñÇý¶¯µÄÓ¦ÓóÌÐò£¿µÄÏêϸÄÚÈÝ£¬¸ü¶àÇë¹Ø×¢±¾ÍøÄÚÆäËüÏà¹ØÎÄÕ£¡