Slide 1

Slide 1 text

LaravelͰ΢ΣϒΞϓϦέʔ γϣϯΛͭ͘Δͱ͖ͷϕετϓϥ ΫςΟεΛ୳Δ in 2018 Cloud Developer - Laravel #1
 nunulk

Slide 2

Slide 2 text

ຊ೔ͷτϐοΫ  ࣗݾ঺հ  -BSBWFMͷಛ௕ʹ͍ͭͯ  -BSBWFMͷΞʔΩςΫνϟ֓ཁ  -BSBWFMͰ΢ΣϒΞϓϦέʔγϣϯΛͭ͘Δͱ͖ͷϕετ ϓϥΫςΟεΛ୳Δ

Slide 3

Slide 3 text

ຊ೔ͷΰʔϧ  -BSBWFMͷਓؾͷཧ༝Λ஌Δ  -BSBWFMͷΞʔΩςΫνϟΛ஌Δ  -BSBWFMͰ΢ΣϒΞϓϦέʔγϣϯΛͭ͘Δͱ͖ͷΑΓ Α͍ઃܭɾ࣮૷ࢦ਑ΛΠϝʔδͰ͖ΔΑ͏ʹͳΔ

Slide 4

Slide 4 text

ࣗݾ঺հ am('nunulk(͵͵Δ͘)')
 ->workAs('a freelance programmer') ->tackleComplexityOfSoftware() ->with([ 'Laravel',
 ‘Vue.js’, ]);

Slide 5

Slide 5 text

DogHuggy

Slide 6

Slide 6 text

SCOUTER

Slide 7

Slide 7 text

Laravelͷಛ௕

Slide 8

Slide 8 text

Laravelͷಛ௕

Slide 9

Slide 9 text

Laravelͷಛ௕

Slide 10

Slide 10 text

Laravelͷಛ௕ l5IF1)1'SBNFXPSL'PS8FC"SUJTBOTz w ΦʔϧΠϯύοέʔδ w ߴ͍ੜ࢈ੑ w ׆ൃͳίϛϡχςΟ

Slide 11

Slide 11 text

Laravelͷಛ௕ w 3VCZPO3BJMT4JOBUSBʹӨڹΛड͚͍ͯΔ ‣ &MPRVFOU03.ɺΫϩʔδϟϕʔεͷϧʔςΟϯά ɺFUD w ಺෦Ͱଟ͘ͷ4ZNGPOZίϯϙʔωϯτΛར༻͠ɺ֦ு͠ ͍ͯΔ ‣ 3FRVFTU 3FTQPOTF $PNNBOE FUD w ๛෋ͳϔϧύʔΫϥε ‣ 'BDBEF $PMMFDUJPO 'MVFOU 0QUJPOBM FUD

Slide 12

Slide 12 text

Laravelͷಛ௕ w 7VFKTΛࠝแ͍ͯ͠Δ ‣ -BSBWFM.JYͰϏϧυઃఆΛ؆ૉԽɺϔϧύʔؔ਺Λఏڙ w ๛෋ͳΦϑΟγϟϧύοέʔδ ‣ $BTIJFS &OWPZ 1BTTQPSU 4PDJBMJUF FUD w ૉૣ͍ϦϦʔεαΠΫϧ ‣ ͓Αͦ൒೥ʹճ ‣ -54͸೥

Slide 13

Slide 13 text

LaravelͷΞʔΩςΫνϟ֓ཁ

Slide 14

Slide 14 text

Router Middleware Request Kernel Controller Response Model Event Job View Resource

Slide 15

Slide 15 text

Routing 
 Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index')->name('home');

Slide 16

Slide 16 text

Middleware public function handle($request, Closure $next, $guard = null) { if (Auth::guard($guard)->check()) { return redirect('/home'); } return $next($request); }

Slide 17

Slide 17 text

Request public function authorize() { return true; } public function rules() { return [ 'subject' => 'required', 'priority' => ‘required|in:high,normal,low’, 'status' => ‘required|in:open,in_progress,close’, 'due_to' => ‘nullable|date', ‘assigned_to' => ‘nullable|exists:users,id’, 'description' => 'nullable|max:800', ]; }

Slide 18

Slide 18 text

Controller public function create(CreateTaskRequest $request) { $task = new Task(); $task->subject = $request->input('subject'); $task->assigned_to = $request->input(‘assigned_to'); $task->priority = $request->input('priority'); $task->status = $request->input('status'); $task->due_to = $request->input('due_to'); $task->description = $request->input('description'); $task->created_by = Auth::id(); $task->save();
 return new JsonResponse($task, Response::HTTP_CREATED); }

Slide 19

Slide 19 text

Event public function create(CreateTaskRequest $request) { $task = new Task();
 // (snip)
 $task->save();
 TaskCreated::dispatch($task);
 return new JsonResponse($task, Response::HTTP_CREATED); }

Slide 20

Slide 20 text

EventListener public function handle(TaskCreatedEvent $event) { $assignee = $event->task->assignee; if (is_null($assignee)) { return; } $assignee->notify(new TaskCreated($event->task)); }

Slide 21

Slide 21 text

LaravelͰ΢ΣϒΞϓϦέʔγϣϯ Λͭ͘Δͱ͖ͷϕετϓϥΫςΟεΛ ୳Δ

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

ϕετϓϥΫςΟεͷ୳͠ํ •ϕετϓϥΫςΟε͸έʔεόΠέʔε •͕ͩɺ͋Δ͍ͯͲ͸ύλʔϯԽͰ͖Δ •ࣗ෼ʢνʔϜʣͷதͰɺج४ΛఆΊ͓ͯ͘͜ͱ͕େࣄ •ܦݧ΍஌ࣝΛ૿΍͠ɺΞοϓσʔτ͍ͯ͘͠ •ҙࣝ෇͚ͱͯ͠͸ʮϕετʯͰ͸ͳ͘ʮϕλʔʯ

Slide 24

Slide 24 text

ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ 3.Ͱ͖Δ͚ͩτϦοΩʔʹͳΒͳ͍Α͏ʹ͢Δ

Slide 25

Slide 25 text

ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ ‣ ެࣜυΩϡϝϯτͷίʔυΛਅࣅΔ ‣ ϑϨʔϜϫʔΫͷઃܭࢥ૝Λཧղ͢Δ ‣ Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷৼΔ෣͍Λม͑ͳ͍

Slide 26

Slide 26 text

ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ ‣ ਆΫϥεΛͭ͘Βͳ͍ ‣ ґଘؔ܎ΛͰ͖Δ͚ͩগͳ͘͢Δ ‣ ςετΛॻ͖΍͍͢Α͏ʹ͢Δ

Slide 27

Slide 27 text

ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ 3.Ͱ͖Δ͚ͩτϦοΩʔʹͳΒͳ͍Α͏ʹ͢Δ ‣ Ͱ͖Δ͚ͩՄಡੑߴ͘ॻ͚ΔΑ͏ʹઃܭ͢Δ ‣ ໎ͬͨΒγϯϓϧͳํΛબ୒͢Δ ‣ τϦοΩʔͳॲཧ͸ӅṭʢہॴԽʣ͢Δ

Slide 28

Slide 28 text

λεΫ؅ཧΞϓϦέʔγϣϯΛྫʹ Ұॹʹߟ͑ͯΈ·͠ΐ͏

Slide 29

Slide 29 text

λεΫΛੜ੒͢Δͱ͖ͷόϦσʔγϣϯ

Slide 30

Slide 30 text

Request (before) public function authorize() { return true; } public function rules() { return [ 'subject' => 'required', 'priority' => ‘required|in:high,normal,low’, 'status' => ‘required|in:open,in_progress,close’, 'due_to' => ‘nullable|date', ‘assigned_to' => ‘nullable|exists:users,id’, 'description' => 'nullable|max:800', ]; }

Slide 31

Slide 31 text

Request (after) // CreateTaskRequest public function authorize() { return true; } public function rules() { return [ ‘subject' => ‘required|max:255’, 'priority' => ['required', Rule::in(Priority::values())], 'status' => ['required', Rule::in(Status::values())], 'due_to' => ‘nullable|date’, ‘assigned_to' => ‘nullable|exists:users,id’, 'description' => ‘nullable|max:800', ]; }

Slide 32

Slide 32 text

Request w όϦσʔγϣϯʹ͓͍ͯɺྻڍܕͷ஋͕ଥ౰͔Ͳ͏͔͸ 3VMFJOΛ࢖ͬͯɺϞσϧ͔Βऔಘ͢ΔΑ͏ʹ͢Δ

Slide 33

Slide 33 text

ΤϯςΟςΟΛੜ੒͢Δͱ͖ͷ $POUSPMMFSͱ3FRVFTUͱͷ࿈ܞ

Slide 34

Slide 34 text

Controller (before) public function create(CreateTaskRequest $request) { $task = new Task(); $task->subject = $request->input('subject'); $task->assigned_to = $request->input(‘assigned_to'); $task->priority = $request->input('priority'); $task->status = $request->input('status'); $task->due_to = $request->input('due_to'); $task->description = $request->input('description'); $task->created_by = Auth::id(); $task->save();
 return new JsonResponse($task, Response::HTTP_CREATED); }

Slide 35

Slide 35 text

Controller (after) public function create(CreateTaskRequest $request) { $task = $request->makeTask(); $task->save();
 return response()->json($task, Response::HTTP_CREATED); }

Slide 36

Slide 36 text

Controller (after) class CreateTaskRequest extends FormRequest { public function makeTask(): Task { return new Task([
 ‘created_by' => $this->user()->id
 + $this->validated()
 ]); } }

Slide 37

Slide 37 text

Controller (before) public function show($id) { $task = Task::findOrFail($id); // snip return $task; }

Slide 38

Slide 38 text

Controller (after) public function show(Task $task) {
 // snip return $task; }

Slide 39

Slide 39 text

Controller w ΤϯςΟςΟͷϓϩύςΟ͸ɺͰ͖Δ͚ͩ·ͱΊͯ 3FRVFTU͔Βऔಘ͠ɺมߋՕॴΛগͳ͘͢ΔΑ͏ʹ͢Δ w ϞσϧόΠϯσΟϯάΛੵۃతʹ࢖͍͖ͬͯ·͠ΐ͏

Slide 40

Slide 40 text

&WFOU+PC/PUJpDBUJPO
 ͷ࢖͍෼͚ͱ໋໊

Slide 41

Slide 41 text

Event/Job/Notification public function create(CreateTaskRequest $request) { $task = $request->makeTask();
 $task->save();
 TaskCreated::dispatch($task);
 return response()->json($task, Response::HTTP_CREATED); }

Slide 42

Slide 42 text

EventListener (before) public function handle(TaskCreatedEvent $event) { UpdateTaskAggregates::dispatch($task);
 $assignee = $event->task->assignee; if (is_null($assignee)) { return; } $assignee->notify(new TaskCreated($event->task)); }

Slide 43

Slide 43 text

EventListener (after) protected $listen = [ 'App\Events\TaskCreated' => [ 'App\Listeners\Task\UpdateTaskAggregates', 'App\Listeners\Task\SendTaskCreatedNotification', ], ];

Slide 44

Slide 44 text

EventListener (after) class UpdateTaskAggregates implements ShouldQueue { public function handle(TaskCreatedEvent $event) { UpdateTaskAggregatesJob::dispatch($task);
 } }
 
 class SendTaskCreatedNotification implements ShouldQueue { public function handle(TaskCreatedEvent $event) { $assignee = $event->task->assignee; if (is_null($assignee)) { return; } $assignee->notify(new TaskCreated($event->task)); } }

Slide 45

Slide 45 text

Event/Job/Notification w ॲཧ్͕தͰࣦഊ͢Δ͜ͱΛߟྀ͠ɺಉҰϦεφͰෳ਺ͷ ॲཧΛͤͣɺϦεφΛ෼͚Δ w &WFOU͸$POUSPMMFSʹରԠ͢ΔΑ͏ʹ໋໊͢Δʢݱࡏ෼ࢺ ܕͰऴΘΔΑ͏ʹʣ
 ྫʣ5BTL$SFBUF$POUSPMMFS5BTL$SFBUFE w +PC͸ৼΔ෣͍͕ࣝผ͢ΔΑ͏ʹ໋໊͢Δʢಈࢺ͔Β࢝Ί Δʣ
 ྫʣ6QEBUF5BTL"HHSFHBUFT w /PUJpDBUJPO͸&WFOUͱಉ໋໊͡

Slide 46

Slide 46 text

&MPRVFOUͰΫΤϦΛ૊ΈཱͯΔ

Slide 47

Slide 47 text

Model (before) 
 public function search(SearchTaskRequest $request) { $query = Task::latest(); $priority = $request->input('priority'); if ($priority) { $query->where('priority', $priority); } $dueToFrom = $request->input(‘due_to.from'); if ($dueToFrom) { $query->where('due_to', ‘>=‘, $dueToFrom); } $dueToTo = $request->input(‘due_to.to’); if ($dueToTo) { $query->where('due_to', ‘<=‘, $dueToTo); } return $query->get(); }

Slide 48

Slide 48 text

Model (after) 
 class SearchTaskQueryBuilder { private $params; public function __construct(array $params) { $this->params = $params; } public function build(Builder $builder): Builder { // ͜͜ͰΫΤϦΛϏϧυ͢Δ
 } }


Slide 49

Slide 49 text

Model (after) 
 // Task public function scopeSearch(
 Builder $query, SearchTaskQueryBuilder $builder) { return $builder->build($query); }
 
 // Task\SearchTaskController
 public function __invoke(SearchTaskRequest $request) { return Task::search($request->createQueryBuilder())->get(); }

Slide 50

Slide 50 text

Model w υϝΠϯ಺ͰҙຯΛ࣋ͭΫΤϦͷ࣮૷͸ΫΤϦείʔϓϝ ιουʹด͡ࠐΊΔ w ΫΤϦͷߏங͕ෳࡶʹͳͬͨΒɺଞͷΫϥεʹ೚ͤΔ͜ ͱ΋Ͱ͖Δ

Slide 51

Slide 51 text

ΞΫηαͱϛϡʔςʔλΛ࢖͏

Slide 52

Slide 52 text

Model (before) $ php artisan tinker Psy Shell v0.9.7 (PHP 7.1.16 — cli) by Justin Hileman >>> dump($task->priority) => "normal"

Slide 53

Slide 53 text

Model (after) $ php artisan tinker Psy Shell v0.9.7 (PHP 7.1.16 — cli) by Justin Hileman >>> dump($task->priority) App\Models\Task\Priority {#2878 #value: "normal" }

Slide 54

Slide 54 text

Model (after) // Task /** * @param $value * @return Priority * @throws \UnexpectedValueException */ public function getPriorityAttribute(string $value): Priority { return new Priority($value); } /** * @param Priority $priority * @return void */ public function setPriorityAttribute(Priority $priority) { $this->attributes['priority'] = $priority->getValue(); }

Slide 55

Slide 55 text

Model w ΞΫηαͱϛϡʔςʔλΛ࢖ͬͯϓϩύςΟΛϓϦϛςΟ ϒܕ͔ΒυϝΠϯͷܕ΁ॻ͖׵͑Δ͜ͱ͕Ͱ͖Δ w ΞΫηαΛར༻ͯ͠ɺࢉग़ϓϩύςΟΛѻ͏͜ͱ΋Ͱ͖Δ

Slide 56

Slide 56 text

%*αʔϏείϯςφ

Slide 57

Slide 57 text

DI (before) 
 class ExternalItsController extends Controller { private $issueTracker; public function __construct() { $this->issueTracker = new GitHub(); } public function index() { // snip
 } }


Slide 58

Slide 58 text

DI (after) 
 class ExternalItsController extends Controller { private $issueTracker; public function __construct(IssueTracker $issueTracker) { $this->issueTracker = $issueTracker; } public function index() {
 $issueTracker = app(IssueTracker::class); // snip
 } }


Slide 59

Slide 59 text

DI (after) class AppServiceProvider extends ServiceProvider { public function register() { $this->app->bind(IssueTracker::class, function () { return new GitHub(); }); } }

Slide 60

Slide 60 text

DI (after) class AppServiceProvider extends ServiceProvider { public function register() { $this->app ->when(ExternalItsController::class) ->needs(IssueTracker::class) ->give(function () { return new GitHub(); }); } }

Slide 61

Slide 61 text

ͦͷଞ

Slide 62

Slide 62 text

ͦͷଞ w 1)16OJUΛ֦ுͯ͠ɺςετͷ͠΍͕͢͞Ξοϓ͍ͯ͠Δ w γϯϓϧͳ͕Β΋πϘΛԡ͑ͨ͞#MBEFςϯϓϨʔτΤϯ δϯ w "SSɺ4USɺ$PMMFDUJPOͳͲͷศརͳϔϧύʔΫϥε΍ؔ਺ ͳͲͳͲ ͝ڵຯ͋Δํ͸ௐ΂ͯΈ͍ͯͩ͘͞

Slide 63

Slide 63 text

·ͱΊ

Slide 64

Slide 64 text

·ͱΊ w ·ͣ͸-BSBWFMͰͳʹ͕Ͱ͖Δͷ͔Λ஌Δ w ෳ਺ͷબ୒ࢶͷத͔Βɺzϕλʔzͱ൑அͨ͠΋ͷΛબͿ w ೔ʑ஌ࣝ΍ܦݧΛ΋ͱʹΞοϓσʔτ͍ͯ͘͠