Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Finding Laravel Best Practices in 2018
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
nunulk
September 08, 2018
Technology
1.8k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Finding Laravel Best Practices in 2018
nunulk
September 08, 2018
More Decks by nunulk
See All by nunulk
Laravelでテストしやすいコードを書く5 / 5 tips of building testable modules in Laravel
nunulk
0
350
Design It! in a nutshell
nunulk
1
310
PHP Getting Faster
nunulk
0
290
How does learning English broaden your world?
nunulk
0
420
Testing on Laravel
nunulk
1
1.6k
Vue.js + TypeScript + Firebase
nunulk
0
970
Nuxt.js in TypeScript
nunulk
1
460
A startup meets Laravel + Vue.js
nunulk
1
2.1k
Unit Testing Laravel
nunulk
0
520
Other Decks in Technology
See All in Technology
検証フェーズはAIの回答を判断するための学習機会
toru_kubota
2
220
Account Factory for Terraformによる 標準化されたアカウント発行の自動化
pensuke628
0
120
「とりあえず動く」の先へ。 AI時代のチーム開発と内部設計/2026-slsdays
slsops
0
100
Argo CDとAtlantisで実現するインフラ管理のセルフサービス化──小規模SREチームで支えるプラットフォーム
cassius7
0
270
AI 時代の Azure エンジニアリング ~ 私たちは何を磨き、何を任せるのか ~
chack411
1
290
KanaAI
shreyas1009
0
140
企業の現実世界をグラフで写し取る
sansantech
PRO
0
240
HacobuにおけるFDEとは/登壇資料(戸井田 裕貴)
hacobu
PRO
1
700
20260930_Gemma4_Hands-on
tsho
0
210
React Nativeでの OTA Updateって、 どう説明する?
ichiki1023
0
130
AIに書かせて、プラットフォームで縛る ― EKSプラットフォームで実践した責任境界と権限設計
elmodev09
1
1.1k
サーバーフルコンピューティング?AWS Lambda
iwatatomoya
0
120
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
440
Being A Developer After 40
akosma
91
590k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
Claude Code のすすめ
schroneko
67
230k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
520
Documentation Writing (for coders)
carmenintech
77
5.6k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
Making the Leap to Tech Lead
cromwellryan
135
10k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
290
Transcript
LaravelͰΣϒΞϓϦέʔ γϣϯΛͭ͘Δͱ͖ͷϕετϓϥ ΫςΟεΛ୳Δ in 2018 Cloud Developer - Laravel #1
nunulk
ຊͷτϐοΫ ࣗݾհ -BSBWFMͷಛʹ͍ͭͯ -BSBWFMͷΞʔΩςΫνϟ֓ཁ -BSBWFMͰΣϒΞϓϦέʔγϣϯΛͭ͘Δͱ͖ͷϕετ ϓϥΫςΟεΛ୳Δ
ຊͷΰʔϧ -BSBWFMͷਓؾͷཧ༝ΛΔ -BSBWFMͷΞʔΩςΫνϟΛΔ -BSBWFMͰΣϒΞϓϦέʔγϣϯΛͭ͘Δͱ͖ͷΑΓ Α͍ઃܭɾ࣮ࢦΛΠϝʔδͰ͖ΔΑ͏ʹͳΔ
ࣗݾհ <?php $I->am('nunulk(͵͵Δ͘)') ->workAs('a freelance programmer') ->tackleComplexityOfSoftware() ->with([ 'Laravel', ‘Vue.js’,
]);
DogHuggy
SCOUTER
Laravelͷಛ
Laravelͷಛ
Laravelͷಛ
Laravelͷಛ l5IF1)1'SBNFXPSL'PS8FC"SUJTBOTz w ΦʔϧΠϯύοέʔδ w ߴ͍ੜ࢈ੑ w ׆ൃͳίϛϡχςΟ
Laravelͷಛ w 3VCZPO3BJMT4JOBUSBʹӨڹΛड͚͍ͯΔ ‣ &MPRVFOU03.ɺΫϩʔδϟϕʔεͷϧʔςΟϯά ɺFUD w ෦Ͱଟ͘ͷ4ZNGPOZίϯϙʔωϯτΛར༻͠ɺ֦ு͠ ͍ͯΔ ‣
3FRVFTU 3FTQPOTF $PNNBOE FUD w ๛ͳϔϧύʔΫϥε ‣ 'BDBEF $PMMFDUJPO 'MVFOU 0QUJPOBM FUD
Laravelͷಛ w 7VFKTΛࠝแ͍ͯ͠Δ ‣ -BSBWFM.JYͰϏϧυઃఆΛ؆ૉԽɺϔϧύʔؔΛఏڙ w ๛ͳΦϑΟγϟϧύοέʔδ ‣ $BTIJFS &OWPZ
1BTTQPSU 4PDJBMJUF FUD w ૉૣ͍ϦϦʔεαΠΫϧ ‣ ͓Αͦʹճ ‣ -54
LaravelͷΞʔΩςΫνϟ֓ཁ
Router Middleware Request Kernel Controller Response Model Event Job View
Resource
Routing Route::get('/', function () { return view('welcome'); }); Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
Middleware public function handle($request, Closure $next, $guard = null) {
if (Auth::guard($guard)->check()) { return redirect('/home'); } return $next($request); }
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', ]; }
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); }
Event public function create(CreateTaskRequest $request) { $task = new Task();
// (snip) $task->save(); TaskCreated::dispatch($task); return new JsonResponse($task, Response::HTTP_CREATED); }
EventListener public function handle(TaskCreatedEvent $event) { $assignee = $event->task->assignee; if
(is_null($assignee)) { return; } $assignee->notify(new TaskCreated($event->task)); }
LaravelͰΣϒΞϓϦέʔγϣϯ Λͭ͘Δͱ͖ͷϕετϓϥΫςΟεΛ ୳Δ
None
ϕετϓϥΫςΟεͷ୳͠ํ •ϕετϓϥΫςΟεέʔεόΠέʔε •͕ͩɺ͋Δ͍ͯͲύλʔϯԽͰ͖Δ •ࣗʢνʔϜʣͷதͰɺج४ΛఆΊ͓ͯ͘͜ͱ͕େࣄ •ܦݧࣝΛ૿͠ɺΞοϓσʔτ͍ͯ͘͠ •ҙ͚ࣝͱͯ͠ʮϕετʯͰͳ͘ʮϕλʔʯ
ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ 3.Ͱ͖Δ͚ͩτϦοΩʔʹͳΒͳ͍Α͏ʹ͢Δ
ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ ‣ ެࣜυΩϡϝϯτͷίʔυΛਅࣅΔ ‣ ϑϨʔϜϫʔΫͷઃܭࢥΛཧղ͢Δ ‣ Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷৼΔ͍Λม͑ͳ͍
ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ ‣ ਆΫϥεΛͭ͘Βͳ͍ ‣ ґଘؔΛͰ͖Δ͚ͩগͳ͘͢Δ ‣ ςετΛॻ͖͍͢Α͏ʹ͢Δ
ϕετϓϥΫςΟεͷ୳͠ํ 1.Ͱ͖Δ͚ͩϑϨʔϜϫʔΫͷ࡞๏ʹ߹ΘͤΔ 2.Ͱ͖Δ͚ͩมߋ༰қੑ͕ߴ͘ͳΔΑ͏ʹ͢Δ 3.Ͱ͖Δ͚ͩτϦοΩʔʹͳΒͳ͍Α͏ʹ͢Δ ‣ Ͱ͖Δ͚ͩՄಡੑߴ͘ॻ͚ΔΑ͏ʹઃܭ͢Δ ‣ ໎ͬͨΒγϯϓϧͳํΛબ͢Δ ‣ τϦοΩʔͳॲཧӅṭʢہॴԽʣ͢Δ
λεΫཧΞϓϦέʔγϣϯΛྫʹ Ұॹʹߟ͑ͯΈ·͠ΐ͏
λεΫΛੜ͢Δͱ͖ͷόϦσʔγϣϯ
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', ]; }
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', ]; }
Request w όϦσʔγϣϯʹ͓͍ͯɺྻڍܕͷ͕ଥ͔Ͳ͏͔ 3VMFJOΛͬͯɺϞσϧ͔Βऔಘ͢ΔΑ͏ʹ͢Δ
ΤϯςΟςΟΛੜ͢Δͱ͖ͷ $POUSPMMFSͱ3FRVFTUͱͷ࿈ܞ
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); }
Controller (after) public function create(CreateTaskRequest $request) { $task = $request->makeTask();
$task->save(); return response()->json($task, Response::HTTP_CREATED); }
Controller (after) class CreateTaskRequest extends FormRequest { public function makeTask():
Task { return new Task([ ‘created_by' => $this->user()->id + $this->validated() ]); } }
Controller (before) public function show($id) { $task = Task::findOrFail($id); //
snip return $task; }
Controller (after) public function show(Task $task) { // snip return
$task; }
Controller w ΤϯςΟςΟͷϓϩύςΟɺͰ͖Δ͚ͩ·ͱΊͯ 3FRVFTU͔Βऔಘ͠ɺมߋՕॴΛগͳ͘͢ΔΑ͏ʹ͢Δ w ϞσϧόΠϯσΟϯάΛੵۃతʹ͍͖ͬͯ·͠ΐ͏
&WFOU+PC/PUJpDBUJPO ͷ͍͚ͱ໋໊
Event/Job/Notification public function create(CreateTaskRequest $request) { $task = $request->makeTask(); $task->save();
TaskCreated::dispatch($task); return response()->json($task, Response::HTTP_CREATED); }
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)); }
EventListener (after) protected $listen = [ 'App\Events\TaskCreated' => [ 'App\Listeners\Task\UpdateTaskAggregates',
'App\Listeners\Task\SendTaskCreatedNotification', ], ];
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)); } }
Event/Job/Notification w ॲཧ్͕தͰࣦഊ͢Δ͜ͱΛߟྀ͠ɺಉҰϦεφͰෳͷ ॲཧΛͤͣɺϦεφΛ͚Δ w &WFOU$POUSPMMFSʹରԠ͢ΔΑ͏ʹ໋໊͢Δʢݱࡏࢺ ܕͰऴΘΔΑ͏ʹʣ ྫʣ5BTL$SFBUF$POUSPMMFS5BTL$SFBUFE w +PCৼΔ͍͕ࣝผ͢ΔΑ͏ʹ໋໊͢Δʢಈࢺ͔Β࢝Ί
Δʣ ྫʣ6QEBUF5BTL"HHSFHBUFT w /PUJpDBUJPO&WFOUͱಉ໋໊͡
&MPRVFOUͰΫΤϦΛΈཱͯΔ
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(); }
Model (after) class SearchTaskQueryBuilder { private $params; public function
__construct(array $params) { $this->params = $params; } public function build(Builder $builder): Builder { // ͜͜ͰΫΤϦΛϏϧυ͢Δ } }
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(); }
Model w υϝΠϯͰҙຯΛ࣋ͭΫΤϦͷ࣮ΫΤϦείʔϓϝ ιουʹด͡ࠐΊΔ w ΫΤϦͷߏங͕ෳࡶʹͳͬͨΒɺଞͷΫϥεʹͤΔ͜ ͱͰ͖Δ
ΞΫηαͱϛϡʔςʔλΛ͏
Model (before) $ php artisan tinker Psy Shell v0.9.7 (PHP
7.1.16 — cli) by Justin Hileman >>> dump($task->priority) => "normal"
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" }
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(); }
Model w ΞΫηαͱϛϡʔςʔλΛͬͯϓϩύςΟΛϓϦϛςΟ ϒܕ͔ΒυϝΠϯͷܕॻ͖͑Δ͜ͱ͕Ͱ͖Δ w ΞΫηαΛར༻ͯ͠ɺࢉग़ϓϩύςΟΛѻ͏͜ͱͰ͖Δ
%*αʔϏείϯςφ
DI (before) class ExternalItsController extends Controller { private $issueTracker;
public function __construct() { $this->issueTracker = new GitHub(); } public function index() { // snip } }
DI (after) class ExternalItsController extends Controller { private $issueTracker;
public function __construct(IssueTracker $issueTracker) { $this->issueTracker = $issueTracker; } public function index() { $issueTracker = app(IssueTracker::class); // snip } }
DI (after) class AppServiceProvider extends ServiceProvider { public function register()
{ $this->app->bind(IssueTracker::class, function () { return new GitHub(); }); } }
DI (after) class AppServiceProvider extends ServiceProvider { public function register()
{ $this->app ->when(ExternalItsController::class) ->needs(IssueTracker::class) ->give(function () { return new GitHub(); }); } }
ͦͷଞ
ͦͷଞ w 1)16OJUΛ֦ுͯ͠ɺςετͷ͕͢͠͞Ξοϓ͍ͯ͠Δ w γϯϓϧͳ͕ΒπϘΛԡ͑ͨ͞#MBEFςϯϓϨʔτΤϯ δϯ w "SSɺ4USɺ$PMMFDUJPOͳͲͷศརͳϔϧύʔΫϥεؔ ͳͲͳͲ ͝ڵຯ͋ΔํௐͯΈ͍ͯͩ͘͞
·ͱΊ
·ͱΊ w ·ͣ-BSBWFMͰͳʹ͕Ͱ͖Δͷ͔ΛΔ w ෳͷબࢶͷத͔Βɺzϕλʔzͱஅͨ͠ͷΛબͿ w ʑࣝܦݧΛͱʹΞοϓσʔτ͍ͯ͘͠