Slide 1

Slide 1 text

Jake Bennett jacobbennett

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Laravel News Podcast North Meets South

Slide 4

Slide 4 text

State Machines

Slide 5

Slide 5 text

Story Time

Slide 6

Slide 6 text

The Problem

Slide 7

Slide 7 text

The Pattern

Slide 8

Slide 8 text

The Implementation

Slide 9

Slide 9 text

The Problem

Slide 10

Slide 10 text

The Problem Invoice System

Slide 11

Slide 11 text

The Problem Building Block of our Software System Entity

Slide 12

Slide 12 text

The Problem Action Something that triggers a speci fi c response

Slide 13

Slide 13 text

The Problem class Invoice extends Model Entity

Slide 14

Slide 14 text

The Problem Actions Create - User creates an Invoice Edit - Update our Invoice Details Finalize - User fi nalizes Invoice to make it ready for payment Pay - Customer pays the Invoice

Slide 15

Slide 15 text

class InvoiceController extends Controller { public function store(CreateInvoiceRequest $request) { Invoice::create($request->validate()); return redirect()->route('invoice.index'); } public function update(UpdateInvoiceRequest $request, Invoice $invoice) { $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } }

Slide 16

Slide 16 text

class InvoiceController extends Controller { public function store(CreateInvoiceRequest $request) { Invoice::create($request->validate()); return redirect()->route('invoice.index'); } public function update(UpdateInvoiceRequest $request, Invoice $invoice) { $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } }

Slide 17

Slide 17 text

class InvoiceController extends Controller { public function store(CreateInvoiceRequest $request) { Invoice::create($request->validate()); return redirect()->route('invoice.index'); } public function update(UpdateInvoiceRequest $request, Invoice $invoice) { $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } }

Slide 18

Slide 18 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 19

Slide 19 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 20

Slide 20 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 21

Slide 21 text

class InvoiceController extends Controller { // ... public function update(UpdateInvoiceRequest $request, Invoice $invoice) { $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } // ... }

Slide 22

Slide 22 text

class InvoiceController extends Controller { // ... public function update(UpdateInvoiceRequest $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be updated’); } $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } // ... }

Slide 23

Slide 23 text

class InvoiceController extends Controller { // ... public function update(UpdateInvoiceRequest $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be updated’); } $invoice->update($request->validate()); return redirect()->route('invoice.show', $invoice); } // ... }

Slide 24

Slide 24 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 25

Slide 25 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 26

Slide 26 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 27

Slide 27 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 28

Slide 28 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (blank($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 29

Slide 29 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (blank($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 30

Slide 30 text

The Problem

Slide 31

Slide 31 text

The Problem • Di ffi cult to determine what rules apply when • Duplication of logic every place we want to update Invoice • Code only ever grows in complexity… for example

Slide 32

Slide 32 text

The Problem New Actions Cancel - Invoices that are Uncollectable Void - Invoices sent accidently

Slide 33

Slide 33 text

The Problem What Needs to Change 1. Add new Flags for each Action 2. Add conditionals wherever we update Invoice

Slide 34

Slide 34 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (blank($invoice->finalized_at) || filled($invoice->paid_at)) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 35

Slide 35 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if ( blank($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->uncollectable_at) || filled($invoice->void_at) ) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice));

Slide 36

Slide 36 text

The Problem

Slide 37

Slide 37 text

The Pattern

Slide 38

Slide 38 text

The Pattern What is a State Machine? a State Machine is a way to help us model how a process goes from one state to another state when an event occurs.

Slide 39

Slide 39 text

The Pattern What is a State Machine? A state machine is a way to help us to model our application logic.

Slide 40

Slide 40 text

The Pattern State Diagram

Slide 41

Slide 41 text

The Pattern State Diagram

Slide 42

Slide 42 text

The Pattern State Diagram

Slide 43

Slide 43 text

The Pattern State Diagram

Slide 44

Slide 44 text

The Pattern State Diagram

Slide 45

Slide 45 text

The Pattern State Diagram

Slide 46

Slide 46 text

The Pattern State Diagram

Slide 47

Slide 47 text

The Pattern State Diagram

Slide 48

Slide 48 text

The Pattern State Diagram

Slide 49

Slide 49 text

The Pattern State Diagram

Slide 50

Slide 50 text

The Pattern State Diagram

Slide 51

Slide 51 text

The Pattern State Diagram

Slide 52

Slide 52 text

The Pattern What is a State? A State, models how a system responds to events for a particular point in time.

Slide 53

Slide 53 text

The Pattern What is a State?

Slide 54

Slide 54 text

The Pattern What is a State? A State, models how a system responds to events for a particular point in time.

Slide 55

Slide 55 text

The Pattern

Slide 56

Slide 56 text

The Pattern Apply to our Invoices

Slide 57

Slide 57 text

Diagram Invoice fl ow using a State Diagram The Pattern Apply to our Invoices

Slide 58

Slide 58 text

Events States The Pattern Apply to our Invoices

Slide 59

Slide 59 text

The Pattern Apply to our Invoices States Events • Finalize • Pay • Cancel • Void • Draft • Open • Paid • Void • Uncollectable

Slide 60

Slide 60 text

State Diagram The Pattern

Slide 61

Slide 61 text

State Diagram The Pattern

Slide 62

Slide 62 text

State Diagram The Pattern

Slide 63

Slide 63 text

State Diagram The Pattern

Slide 64

Slide 64 text

State Diagram The Pattern

Slide 65

Slide 65 text

State Diagram The Pattern

Slide 66

Slide 66 text

State Diagram The Pattern

Slide 67

Slide 67 text

State Diagram The Pattern

Slide 68

Slide 68 text

State Diagram The Pattern

Slide 69

Slide 69 text

State Diagram The Pattern

Slide 70

Slide 70 text

State Diagram The Pattern

Slide 71

Slide 71 text

State Diagram The Pattern

Slide 72

Slide 72 text

State Diagram The Pattern

Slide 73

Slide 73 text

State Diagram The Pattern

Slide 74

Slide 74 text

State Diagram The Pattern

Slide 75

Slide 75 text

State Diagram The Pattern

Slide 76

Slide 76 text

State Diagram The Pattern

Slide 77

Slide 77 text

The Pattern

Slide 78

Slide 78 text

The Implementation

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

The Implementation

Slide 82

Slide 82 text

Tracking State The Implementation

Slide 83

Slide 83 text

The Implementation class Invoice

Slide 84

Slide 84 text

The Implementation class Invoice extends Model { protected $attributes = [ 'status' => 'draft', ]; }

Slide 85

Slide 85 text

State Diagram The Implementation

Slide 86

Slide 86 text

State = Class The Implementation

Slide 87

Slide 87 text

State = Class The Implementation

Slide 88

Slide 88 text

Event = Method The Implementation

Slide 89

Slide 89 text

Event = Method The Implementation

Slide 90

Slide 90 text

Event = Method The Implementation interface InvoiceStateContract { function finalize(); function pay(); function void(); function cancel(); }

Slide 91

Slide 91 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 92

Slide 92 text

Event = Method The Implementation

Slide 93

Slide 93 text

Event = Method The Implementation

Slide 94

Slide 94 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 95

Slide 95 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => ‘open']); } function pay() {} function void() {} function cancel() {} }

Slide 96

Slide 96 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => ‘open']); Mail::send(new InvoiceDue($invoice)); } function pay() {} function void() {} function cancel() {} }

Slide 97

Slide 97 text

Event = Method The Implementation

Slide 98

Slide 98 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => ‘open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() {} function void() {} function cancel() {} }

Slide 99

Slide 99 text

Event = Method The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => ‘open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 100

Slide 100 text

Event = Method The Implementation

Slide 101

Slide 101 text

Event = Method The Implementation

Slide 102

Slide 102 text

Event = Method The Implementation class OpenInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 103

Slide 103 text

Event = Method The Implementation

Slide 104

Slide 104 text

Event = Method The Implementation class OpenInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 105

Slide 105 text

Event = Method The Implementation class OpenInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() {} function void() {} function cancel() {} }

Slide 106

Slide 106 text

Event = Method The Implementation

Slide 107

Slide 107 text

Event = Method The Implementation class OpenInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() {} function void() {} function cancel() {} }

Slide 108

Slide 108 text

class OpenInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() { $this->invoice->update(['status' => 'paid']); } function void() { $this->invoice->update(['status' => 'void']); } Event = Method The Implementation

Slide 109

Slide 109 text

{ function finalize() { throw new Exception(); } function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } function void() { $this->invoice->update(['status' => 'void']); } function cancel() { $this->invoice->update(['status' => 'uncollectable']); } Event = Method The Implementation

Slide 110

Slide 110 text

Event = Method The Implementation

Slide 111

Slide 111 text

Event = Method The Implementation

Slide 112

Slide 112 text

Event = Method The Implementation class UncollectableInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 113

Slide 113 text

Event = Method The Implementation class UncollectableInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() {} function void() {} function cancel() { throw new Exception(); } }

Slide 114

Slide 114 text

Event = Method The Implementation

Slide 115

Slide 115 text

Event = Method The Implementation

Slide 116

Slide 116 text

Event = Method The Implementation class UncollectableInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() {} function void() {} function cancel() { throw new Exception(); } }

Slide 117

Slide 117 text

Event = Method The Implementation class UncollectableInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() { $this->invoice->update(['status' => 'paid']); } function void() { $this->invoice->update(['status' => 'void']); }

Slide 118

Slide 118 text

Event = Method The Implementation class UncollectableInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new CancelledInvoicePaid($this->invoice)); } function void() { $this->invoice->update(['status' => 'void']); }

Slide 119

Slide 119 text

Event = Method The Implementation

Slide 120

Slide 120 text

Event = Method The Implementation

Slide 121

Slide 121 text

Event = Method The Implementation class PaidInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} } class VoidInvoiceState implements InvoiceStateContract { function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 122

Slide 122 text

Event = Method The Implementation class PaidInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } } class VoidInvoiceState implements InvoiceStateContract { function finalize() { throw new Exception(); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 123

Slide 123 text

The Implementation

Slide 124

Slide 124 text

The Implementation Cleaning up

Slide 125

Slide 125 text

Cleaning Up The Implementation class BaseInvoiceState { }

Slide 126

Slide 126 text

Cleaning Up The Implementation class BaseInvoiceState { function __construct(public Invoice $invoice) {} }

Slide 127

Slide 127 text

Cleaning Up The Implementation class BaseInvoiceState implements InvoiceStateContract { function __construct(public Invoice $invoice) {} }

Slide 128

Slide 128 text

Cleaning Up The Implementation class BaseInvoiceState implements InvoiceStateContract { function __construct(public Invoice $invoice) {} function finalize() {} function pay() {} function void() {} function cancel() {} }

Slide 129

Slide 129 text

Cleaning Up The Implementation class BaseInvoiceState implements InvoiceStateContract { function __construct(public Invoice $invoice) {} function finalize() { throw new Exception(); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 130

Slide 130 text

Cleaning Up The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => 'open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 131

Slide 131 text

Cleaning Up The Implementation class DraftInvoiceState implements InvoiceStateContract { function finalize() { $this->invoice->update(['status' => 'open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 132

Slide 132 text

Cleaning Up The Implementation class DraftInvoiceState extends BaseInvoiceState { function finalize() { $this->invoice->update(['status' => 'open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 133

Slide 133 text

Cleaning Up The Implementation class DraftInvoiceState extends BaseInvoiceState { function finalize() { $this->invoice->update(['status' => 'open']); Mail::send(new InvoiceDue($this->invoice)); } function pay() { throw new Exception(); } function void() { throw new Exception(); } function cancel() { throw new Exception(); } }

Slide 134

Slide 134 text

Cleaning Up The Implementation class DraftInvoiceState extends BaseInvoiceState { function finalize() { $this->invoice->update(['status' => 'open']); Mail::send(new InvoiceDue($this->invoice)); } }

Slide 135

Slide 135 text

The Implementation Cleaning up

Slide 136

Slide 136 text

The Implementation Model State Machine

Slide 137

Slide 137 text

class Invoice extends Model The Implementation Model State Machine

Slide 138

Slide 138 text

Model State Machine The Implementation class Invoice extends Model { protected $attributes = [ 'status' => 'draft', ]; }

Slide 139

Slide 139 text

Model State Machine The Implementation class Invoice extends Model { protected $attributes = [ 'status' => 'draft', ]; public function state(): InvoiceStateContract { } }

Slide 140

Slide 140 text

Model State Machine The Implementation public function state(): InvoiceStateContract { }

Slide 141

Slide 141 text

Model State Machine The Implementation public function state(): InvoiceStateContract { } return match ($this->status) { 'draft' => new DraftInvoiceState($this), 'open' => new OpenInvoiceState($this), 'paid' => new PaidInvoiceState($this), 'void' => new VoidInvoiceState($this), 'uncollectable' => new UncollectableInvoiceState($this), default => throw new InvalidArgumentException('Invalid status'), };

Slide 142

Slide 142 text

The Implementation Model State Machine $invoice->state()

Slide 143

Slide 143 text

The Implementation Model State Machine

Slide 144

Slide 144 text

The Implementation Usage

Slide 145

Slide 145 text

Usage The Implementation

Slide 146

Slide 146 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->void_at) || filled($invoice->cancelled_at) ) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 147

Slide 147 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->void_at) || filled($invoice->cancelled_at) ) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 148

Slide 148 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->void_at) || filled($invoice->cancelled_at) ) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 149

Slide 149 text

class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if (filled($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->void_at) || filled($invoice->cancelled_at) ) { abort(403, 'Invoice cannot be finalized'); } $invoice->update(['finalized_at' => now()]); Mail::send(new InvoiceDue($invoice)); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 150

Slide 150 text

Usage The Implementation class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->finalize(); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 151

Slide 151 text

Usage The Implementation class FinalizeInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->finalize(); return view('invoice.show', ['invoice' => $invoice]); } }

Slide 152

Slide 152 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if ( blank($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->uncollectable_at) || filled($invoice->void_at) ) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 153

Slide 153 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { if ( blank($invoice->finalized_at) || filled($invoice->paid_at) || filled($invoice->uncollectable_at) || filled($invoice->void_at) ) { abort(403, 'Invoice cannot be paid'); } $invoice->update(['paid_at' => now()]); Mail::send(new InvoicePaid($invoice)); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 154

Slide 154 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->pay(); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 155

Slide 155 text

Event = Method The Implementation

Slide 156

Slide 156 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->pay(); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 157

Slide 157 text

class OpenInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } }

Slide 158

Slide 158 text

class OpenInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } }

Slide 159

Slide 159 text

class OpenInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } }

Slide 160

Slide 160 text

class UncollectableInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new CancelledInvoicePaid($this->invoice)); } } class OpenInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } }

Slide 161

Slide 161 text

class UncollectableInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new CancelledInvoicePaid($this->invoice)); } } class OpenInvoiceState implements InvoiceStateContract { function pay() { $this->invoice->update(['status' => ‘paid']); Mail::send(new InvoicePaid($this->invoice)); } }

Slide 162

Slide 162 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->pay(); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 163

Slide 163 text

class PayInvoiceController extends Controller { public function __invoke(Request $request, Invoice $invoice) { $invoice->state()->pay(); return view('invoice.thanks', ['invoice' => $invoice]); } }

Slide 164

Slide 164 text

The Implementation Event-Action

Slide 165

Slide 165 text

The Implementation Event-State-Action

Slide 166

Slide 166 text

Benefits The Implementation

Slide 167

Slide 167 text

• Di ffi cult to determine what rules apply when • Duplication of logic every place we want to update Invoice • Code only ever grows in complexity The Implementation Benefits

Slide 168

Slide 168 text

• Di ffi cult to determine what rules apply when • Duplication of logic every place we want to update Invoice • Code only ever grows in complexity The Implementation Benefits

Slide 169

Slide 169 text

• Di ffi cult to determine what rules apply when • Duplication of logic every place we want to update Invoice • Code only ever grows in complexity The Implementation Benefits

Slide 170

Slide 170 text

• Di ffi cult to determine what rules apply when • Duplication of logic every place we want to update Invoice • Code only ever grows in complexity The Implementation Benefits

Slide 171

Slide 171 text

State Machines

Slide 172

Slide 172 text

No content

Slide 173

Slide 173 text

No content

Slide 174

Slide 174 text

No content

Slide 175

Slide 175 text

No content

Slide 176

Slide 176 text

No content

Slide 177

Slide 177 text

No content

Slide 178

Slide 178 text

Jake Bennett jacobbennett