Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Finding Laravel Best Practices in 2018
Search
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
340
Design It! in a nutshell
nunulk
1
290
PHP Getting Faster
nunulk
0
290
How does learning English broaden your world?
nunulk
0
410
Testing on Laravel
nunulk
1
1.6k
Vue.js + TypeScript + Firebase
nunulk
0
970
Nuxt.js in TypeScript
nunulk
1
450
A startup meets Laravel + Vue.js
nunulk
1
2.1k
Unit Testing Laravel
nunulk
0
510
Other Decks in Technology
See All in Technology
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
3
2k
【NRUG vol.18】なぜ多くのオブザーバビリティ導入は失敗するのか
nrug_member
0
120
失敗を資産に変えるClaude Code
shinyasaita
0
620
気づかぬうちにセキュリティ負債を生むAPIキー運用
sgwrmctk
0
120
小さく始める AI 活用推進 ― 日経電子版 Web チームの事例/nikkei-tech-talk47
nikkei_engineer_recruiting
0
250
自宅LLMの話
jacopen
1
510
エラーバジェットのアラートのタイミングを考える.pdf
kairim0
0
140
やさしいA2A入門
minorun365
PRO
12
1.8k
FDE という解 ― 暗黙知と明示知をつなぐ、伴走型エンジニアリング ―
otanet
0
150
2026.06.13_AI時代に事業会社が「SIer出身エンジニア」を求める理由 / Why Businesses Seek Engineers with a System Integrator Background in the AI Era
jumtech
0
1.1k
スキルと MCP ツール、責務をどう分けるか? AI が迷わないインターフェース設計の戦略
cdataj
1
1k
AIの性能が向上しても未解決な組織の重大問題は何か?/An Unsolved Organizational Problem in the Age of AI
moriyuya
4
650
Featured
See All Featured
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
300
The Mindset for Success: Future Career Progression
greggifford
PRO
0
360
Fireside Chat
paigeccino
42
3.9k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
220
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
How STYLIGHT went responsive
nonsquared
100
6.2k
Building the Perfect Custom Keyboard
takai
2
790
Prompt Engineering for Job Search
mfonobong
0
340
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
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 ʑࣝܦݧΛͱʹΞοϓσʔτ͍ͯ͘͠