Laravel.IO A Use-Case Architecture

110
LARAVEL.IO A USE CASE ARCHITECTURE

description

A simple architecture is perfect for a simple application. But, as the application grows in its complexity, the architecture must become more complex in order to prevent it from becoming unmaintainable. In this talk we discuss some ideas for simplifying complex code bases. We also discuss the important distinctions between presentation, service, and domain layers and strategies for separating high-level business policy from implementation. Some Domain-Driven Design topics are discussed, but this is not a talk about DDD. DDD is not about design patterns, but rather is about business analysis, communication, and much more.

Transcript of Laravel.IO A Use-Case Architecture

Page 1: Laravel.IO A Use-Case Architecture

LARAVEL.IOA USE CASE ARCHITECTURE

Page 2: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

HI, I’M SHAWN

Page 3: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

LARAVEL.IO ORIGIN

Page 4: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Laravel.IO Now

LARAVEL.IO FORUM

from Nick Spelt and myself

LIONA (LioBot)

from Sam Evaskitas and Matthew Machuga

LARAVEL WEEKLY NEWSLETTER

by Dries Vints

PODCAST

http://bit.ly/laravelio-podcast

Assets available for contribution at: https://github.com/LaravelIO

Page 5: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

AKA ENGINEERINGMANAGING COMPLEXITY

Page 6: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

FUNCTIONAL REQUIREMENTS

Page 7: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

USE CASES

Page 8: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

ENTITIES

Many objects are not fundamentally defined by their attributes,

but rather by a thread of continuity and identity.

- Eric Evans

Page 9: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PeoplePERSON

Page 10: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Jane Doe

People

Jane Doe

PERSON

Page 11: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Jane Doe

People

Jane DoeJane Doe

PERSON

Jane Doe

Page 12: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Jane Doe

PERSON

Age: 27

Jane Doe

Age: 27

Page 13: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Jane Doe

PERSON

Age: 27

From: NYC

Jane Doe

Age: 27

From: NYC

Page 14: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THE ACTIVERECORD PATTERN

Page 15: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

ID: 1 ID: 2

Jane Doe

PERSON

Age: 27

From: NYC

Jane Doe

Age: 27

From: NYC

People Table

ID

1

2

Age

27

27

From

NYC

NYC

Name

Jane Doe

Jane Doe

Page 16: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

ENTITIES AND ACTIVERECORD

Page 17: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THIS IS NOT DDD

Page 18: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

LAYERED ARCHITECTURE

Page 19: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

A COMMON APPLICATION

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

Page 20: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

DOMAIN

Entities

Repository Interfaces

A COMMON APPLICATION

Page 21: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

SERVICE LAYER

Sending Email

Queueing up Jobs

Repository Implementations

DOMAIN

Entities

Repository Interfaces

A COMMON APPLICATION

Page 22: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

SERVICE LAYER

Sending Email

Queueing up Jobs

Repository Implementations

Commands / Command Bus

DOMAIN

Entities

Repository Interfaces

A COMMON APPLICATION

Page 23: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

A COMMAND ORIENTED INTERFACE

Page 24: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MEAT OF THE APPLICATION

WHAT IS A COMMAND

Page 25: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Controller

Artisan Command

Queue Worker

Whatever

MEAT OF THE APPLICATION

WHAT IS A COMMAND

Page 26: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

WHAT IS A COMMAND

MEAT OF THE APPLICATIONREGISTER MEMBER COMMAND

Page 27: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

WHAT IS A COMMAND

MEAT OF THE APPLICATIONREGISTER MEMBER COMMAND

Page 28: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

WHAT IS A COMMAND

REGISTER MEMBER COMMAND

MEAT OF THE APPLICATION

Page 29: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Some Advantages

- No business policy in your controllers

- Your code shows intent

- A single dedicated flow per use case

- A single point of entry per use case

- Easy to see which use cases are implemented

Page 30: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

COMMAND ANATOMY

Page 31: Laravel.IO A Use-Case Architecture

class RegisterMemberCommand{ public $displayName; public $email; public $password;

public function __construct($displayName, $email, $password) { $this->displayName = $displayName; $this->email = $email; $this->password = $password; }}

Page 32: Laravel.IO A Use-Case Architecture

class RegisterMemberCommand{ public $displayName; public $email; public $password;

public function __construct($displayName, $email, $password) { $this->displayName = $displayName; $this->email = $email; $this->password = $password; }}

Page 33: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

WHAT IS HAPPENING INSIDE?

MEAT OF THE APPLICATION

REGISTER MEMBER COMMAND

Page 34: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THE FINAL DESTINATION

MEAT OF THE APPLICATION

REGISTER MEMBER HANDLER

REGISTER MEMBER COMMAND

Page 35: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THE FINAL DESTINATION

MEAT OF THE APPLICATION

?REGISTER MEMBER COMMAND

REGISTER MEMBER HANDLER

Page 36: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THE TRANSPORT MECHANISM

MEAT OF THE APPLICATION

COMMAND BUSREGISTER MEMBER COMMAND

REGISTER MEMBER HANDLER

Page 37: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

COMMAND BUS IMPLEMENTATION

Page 38: Laravel.IO A Use-Case Architecture

class ExecutionCommandBus implements CommandBus{ private $container; private $mapper;

public function __construct(Container $container,Mapper $mapper) { $this->container = $container; $this->mapper = $mapper; }

public function execute($command) { $this->getHandler($command)->handle($command); }

private function getHandler($command) { $class = $this->mapper->getHandlerClassFor($command); return $this->container->make($class); }

}

Page 39: Laravel.IO A Use-Case Architecture

class ExecutionCommandBus implements CommandBus{ private $container; private $mapper;

public function __construct(Container $container,Mapper $mapper) { $this->container = $container; $this->mapper = $mapper; }

public function execute($command) { $this->getHandler($command)->handle($command); }

private function getHandler($command) { $class = $this->mapper->getHandlerClassFor($command); return $this->container->make($class); }

}

Page 40: Laravel.IO A Use-Case Architecture

class ExecutionCommandBus implements CommandBus{ private $container; private $mapper;

public function __construct(Container $container,Mapper $mapper) { $this->container = $container; $this->mapper = $mapper; }

public function execute($command) { $this->getHandler($command)->handle($command); }

private function getHandler($command) { $class = $this->mapper->getHandlerClassFor($command); return $this->container->make($class); }

}

Page 41: Laravel.IO A Use-Case Architecture

class ExecutionCommandBus implements CommandBus{ private $container; private $mapper;

public function __construct(Container $container,Mapper $mapper) { $this->container = $container; $this->mapper = $mapper; }

public function execute($command) { $this->getHandler($command)->handle($command); }

private function getHandler($command) { $class = $this->mapper->getHandlerClassFor($command); return $this->container->make($class); }

}

Page 42: Laravel.IO A Use-Case Architecture

class ExecutionCommandBus implements CommandBus{ private $container; private $mapper;

public function __construct(Container $container,Mapper $mapper) { $this->container = $container; $this->mapper = $mapper; }

public function execute($command) { $this->getHandler($command)->handle($command); }

private function getHandler($command) { $class = $this->mapper->getHandlerClassFor($command); return $this->container->make($class); }

}

Page 43: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

HOW DOES THE MAPPER KNOW?

Page 44: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

ONE HANDLER PER COMMAND

Page 45: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{

private $memberRepository;

public function __construct(MemberRepository $memberRepository) { $this->memberRepository = $memberRepository; }

public function handle($command) { $member = Member::register(

$command->displayName,

$command->email,

$command->password);

$this->memberRepository->save($member); }}

Page 46: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{

private $memberRepository;

public function __construct(MemberRepository $memberRepository) { $this->memberRepository = $memberRepository; }

public function handle($command) { $member = Member::register(

$command->displayName,

$command->email,

$command->password);

$this->memberRepository->save($member); }}

Page 47: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{

private $memberRepository;

public function __construct(MemberRepository $memberRepository) { $this->memberRepository = $memberRepository; }

public function handle($command) { $member = Member::register(

$command->displayName,

$command->email,

$command->password);

$this->memberRepository->save($member); }}

Page 48: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{

private $memberRepository;

public function __construct(MemberRepository $memberRepository) { $this->memberRepository = $memberRepository; }

public function handle($command) { $member = Member::register(

$command->displayName,

$command->email,

$command->password);

$this->memberRepository->save($member); }}

Page 49: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

return $member; }}

Page 50: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

DOMAIN IMPLICATION

Page 51: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Service Layer DomainPresentation Layer

Flow Review

FLOW REVIEW

PRESENTATION LAYER

SERVICE LAYER DOMAIN

Page 52: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Service Layer DomainPresentation Layer

Command

FLOW REVIEW

PRESENTATION LAYER

SERVICE LAYER DOMAIN

COMMAND

Page 53: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Service Layer DomainPresentation Layer

Command Command Bus

FLOW REVIEW

PRESENTATION LAYER

SERVICE LAYER DOMAIN

COMMAND COMMAND BUS

Page 54: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Service Layer DomainPresentation Layer

Command Command Bus

Command Handler

FLOW REVIEW

PRESENTATION LAYER

SERVICE LAYER DOMAIN

COMMAND COMMAND BUS

COMMANDHANDLER

Page 55: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

FLOW REVIEW

PRESENTATION LAYER

SERVICE LAYER DOMAIN

COMMAND COMMAND BUS

COMMANDHANDLER

ENTITIES

REPOSITORIES

Page 56: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

HANDLING COMPLEX SEQUENCES

Page 57: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Joins

Send Welcome Email

Subscribe to MailChimp

Queue up 7 day Email

MEMBER REGISTERS

SEND WELCOME EMAIL

SUBSCRIBE TO MAILCHIMP

QUEUE UP 7 DAY EMAIL

SIMPLE SEQUENCE

Page 58: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER REPLIES TO THREAD

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

Page 59: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER REPLIES TO THREAD

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

ADD NOTIFICATION DIGEST

QUEUE ENTRY

SEND NO NOTIFICATION

Page 60: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

DOMAIN EVENTS

Page 61: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

TYPICAL PUB-SUB PATTERN

DISPATCH EVENTRAISE EVENT TRIGGER LISTENERS

Page 62: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

SERVICE LAYER

Sending Email

Queueing up Jobs

Repository Implementations

Commands / Command Bus

DOMAIN

Entities

Repository Interfaces

A COMMON APPLICATION

Page 63: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

PRESENTATION LAYER

Controllers

Artisan Commands

Queue Listeners

SERVICE LAYER

Sending Email

Queueing up Jobs

Repository Implementations

Commands / Command Bus

Event Dispatcher

DOMAIN

Entities

Repository Interfaces

Domain Events

A COMMON APPLICATION

Page 64: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Joins

Send Welcome Email

Subscribe to MailChimp

Queue up 7 day Email

MEMBER REGISTERS

SEND WELCOME EMAIL

SUBSCRIBE TO MAILCHIMP

QUEUE UP 7 DAY EMAIL

DOMAIN EVENTS

Page 65: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Joins

Send Welcome Email

Subscribe to MailChimp

Queue up 7 day Email

MEMBER REGISTERS

SEND WELCOME EMAIL

SUBSCRIBE TO MAILCHIMP

QUEUE UP 7 DAY EMAIL

EVENT / LISTENER BREAKDOWN

Page 66: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MemberJoined

Send Welcome Email

Subscribe to MailChimp

Queue up 7 day Email

MemberRegistered

SEND WELCOME EMAIL

SUBSCRIBE TO MAILCHIMP

QUEUE UP 7 DAY EMAIL

EVENT / LISTENER BREAKDOWN

Page 67: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MemberJoined

Send Welcome Email

Subscribe to MailChimp

Queue up 7 day Email

MemberRegistered

SEND WELCOME EMAIL

SUBSCRIBE TO MAILCHIMP

QUEUE UP 7 DAY EMAIL

EVENT / LISTENER BREAKDOWN

Page 68: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MemberJoined

SendWelcomeEmail

SubscribeToMailChimp

SendOneWeekEmail

MemberRegistered

SendWelcomeMail

SubscribeToMailchimp

SendOneWeekEmail

EVENT / LISTENER BREAKDOWN

Page 69: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MemberJoined SendWelcomeEmail

SubscribeToMailChimp

SendOneWeekEmail

Events Listeners

MemberRegistered SendWelcomeMail

SendOneWeekEmail

SubscribeToMailchimp

EVENTS LISTENERS

EVENT / LISTENER BREAKDOWN

Page 70: Laravel.IO A Use-Case Architecture

class MemberRegistered{ public $member;

public function __construct(Member $member) { $this->member = $member; }}

class SendWelcomeEmail implements Listener{ public function handle($event) { Mailer::queue(...); }}

Page 71: Laravel.IO A Use-Case Architecture

class MemberRegistered{ public $member;

public function __construct(Member $member) { $this->member = $member; }}

class SendWelcomeEmail implements Listener{ public function handle($event) { Mailer::queue(...); }}

Page 72: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THROWING DOMAIN EVENTS

Page 73: Laravel.IO A Use-Case Architecture

trait EventGenerator{ protected $pendingEvents = [];

protected function raise($event) { $this->pendingEvents[] = $event; }

public function releaseEvents() { $events = $this->pendingEvents; $this->pendingEvents = []; return $events; }}

Page 74: Laravel.IO A Use-Case Architecture

trait EventGenerator{ protected $pendingEvents = [];

protected function raise($event) { $this->pendingEvents[] = $event; }

public function releaseEvents() { $events = $this->pendingEvents; $this->pendingEvents = []; return $events; }}

Page 75: Laravel.IO A Use-Case Architecture

trait EventGenerator{ protected $pendingEvents = [];

protected function raise($event) { $this->pendingEvents[] = $event; }

public function releaseEvents() { $events = $this->pendingEvents; $this->pendingEvents = []; return $events; }}

Page 76: Laravel.IO A Use-Case Architecture

trait EventGenerator{ protected $pendingEvents = [];

protected function raise($event) { $this->pendingEvents[] = $event; }

public function releaseEvents() { $events = $this->pendingEvents; $this->pendingEvents = []; return $events; }}

Page 77: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ use EventGenerator;

public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

$member->raise(new MemberJoined($member));

return $member; }}

Page 78: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ use EventGenerator;

public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

$member->raise(new MemberRegistered($member));

return $member; }}

Page 79: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ use EventGenerator;

public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

$member->raise(new MemberRegistered($member));

return $member; }}

Page 80: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ use EventGenerator;

public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

$member->raise(new MemberRegistered($member));

return $member; }}

Page 81: Laravel.IO A Use-Case Architecture

class Member extends Eloquent{ use EventGenerator;

public static function register($displayName, $email, $password) { $member = new static([ 'display_name' => $displayName, 'email' => $email, 'password' => $password, ]);

$member->raise(new MemberRegistered($member));

return $member; }}

Page 82: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

EVENT DISPATCHING

Page 83: Laravel.IO A Use-Case Architecture

interface Dispatcher

{

public function addListener($eventName, Listener $listener);

public function dispatch($events);

}

// Register Listeners

$dispatcher = new Dispatcher;

$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);

$dispatcher->addListener('MemberRegistered', new SubscribeToMailchimp);

$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);

// Dispatch Events

$dispatcher->dispatch($events);

Page 84: Laravel.IO A Use-Case Architecture

interface Dispatcher

{

public function addListener($eventName, Listener $listener);

public function dispatch($events);

}

// Register Listeners

$dispatcher = new Dispatcher;

$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);

$dispatcher->addListener('MemberRegistered’, new SubscribeToMailchimp);

$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);

// Dispatch Events

$dispatcher->dispatch($events);

Page 85: Laravel.IO A Use-Case Architecture

interface Dispatcher

{

public function addListener($eventName, Listener $listener);

public function dispatch($events);

}

// Register Listeners

$dispatcher = new Dispatcher;

$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);

$dispatcher->addListener('MemberRegistered’, new SubscribeToMailchimp);

$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);

// Dispatch Events

$dispatcher->dispatch($events);

Page 86: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

THE FULL COMMAND HANDLERHeads Up...

Page 87: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 88: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 89: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 90: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 91: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 92: Laravel.IO A Use-Case Architecture

class RegisterMemberHandler implements Handler{ private $memberRepository; private $dispatcher;

public function __construct(MemberRepository $memberRepository,

Dispatcher $dispatcher) { $this->memberRepository = $memberRepository; $this->dispatcher = $dispatcher; }

public function handle($command) { $member = Member::register( $command->displayName, $command->email, $command->password);

$this->memberRepository->save($member); $this->dispatcher->dispatch($member->releaseEvents()); }}

Page 93: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER REPLIES TO THREAD

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

ADD NOTIFICATION DIGEST

QUEUE ENTRY

SEND NO NOTIFICATION

Page 94: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER REPLIES TO THREAD

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

Page 95: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER REPLIES TO THREAD

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

Page 96: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberRepliedToThread

NOTIFY THREAD SUBSCRIBERS

wNOTIFY TAGGED USERS

COMPLEX SEQUENCE

Page 97: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberRepliedToThread

NOTIFY THREAD SUBSCRIBERS

NOTIFY TAGGED USERS

COMPLEX SEQUENCE

Page 98: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberRepliedToThread

NotifyThreadSubscribers

NotifyTaggedUsers

COMPLEX SEQUENCE

Page 99: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER IS NOTIFIED

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

Page 100: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MEMBER IS NOTIFIED

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

Page 101: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberNotificationSent

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

Page 102: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberNotificationSent

COMPLEX SEQUENCE

SEND NOTIFICATION

EMAIL

Page 103: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Member Replies to Thread

Notify Subscribers

Parse for @username Tags

Send Notification Email

Add Notification Digest Queue Entry

Send No NotificationNotify Tagged Users

MemberNotificationSent

COMPLEX SEQUENCE

SendNotificationEmail

Page 104: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MemberJoined SendWelcomeEmail

SubscribeToMailChimp

SendOneWeekEmail

Events ListenersDOMAIN EVENTS

MemberRepliedToThread NotifyThreadSubscribers

SendNotificationEmail

NotifyTaggedMembers

EVENTS LISTENERS

MemberNotificationSent

Page 105: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Some Disadvantages

- Can be harder to understand what’s happening

- Requires more infrastructure

- Events can be hard to debug

Page 106: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

DOMAIN-DRIVEN DESIGN

Page 107: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

MORE INFORMATION ABOUT DDD

http://verraes.net

http://rosstuck.com

http://dddinphp.org

Domain-Driven Designby Eric Evans

Implementing Domain-Driven Designby Vaughn Vernon

Page 108: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Even More Information

A very quick read + it’s free

http://www.infoq.com/minibooks/domain-driven-design-quickly

Martin Fowler

http://martinfowler.com/bliki/CommandOrientedInterface.html

http://martinfowler.com/eaaDev/DomainEvent.html

Page 109: Laravel.IO A Use-Case Architecture

Tickets are available at http://Laracon.EU

Page 110: Laravel.IO A Use-Case Architecture

Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC

Thank you Laracon 2014!

Hopefully, I talked so ridiculously fast

that there’s time for questions.

Twitter @ShawnMcCool

Special Thanks to Nick Spelt and Mitchell van Wijngaarden