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
[2026 Oracle Technical Deep Dive] VMwareワークロードのOCI移行実践ガイド - OCVSでの継続利用からOCIコンピュートへの移行まで (2026年9月17日開催)
oracle4engineer
PRO
0
120
Lambda MicroVMsが分からなすぎたので使い所を1から考えてみた
tsukuboshi
2
410
データ品質を壊しながらSnowflakeのAIに分析させてみた
kawanago
0
520
[2026 Oracle Technical Deep Dive] OCI AI Resilience -OCIのセキュリティ対策機能をきちんと使いこなす- (2026年9月17日開催)
oracle4engineer
PRO
0
130
大阪オフィスに Unitree Go2 がやってきたので Physical AI やってみた
dafujii
0
320
カンファレンスに参加した後の浮遊感とセルフケア
pauli
0
310
React Nativeでの OTA Updateって、 どう説明する?
ichiki1023
0
150
3つのアプローチで目指す チームを強くするAI駆動開発
thkt
0
110
おそらく日本で唯一のDevRelインターン生として
husengs7
0
170
生成AIを使って「人が」考える技術 ― AI時代の人機共想と実践ノウハウ|UNITT AC2026
ishiirikie
0
550
[AWS 秋のクラウドオペレーション祭り 2026]AWS DevOps Agentで変わるリリースと運用対応 ~リリース管理機能と Directed actions のご紹介~
furuton
3
920
「とりあえず動く」の先へ。 AI時代のチーム開発と内部設計/2026-slsdays
slsops
0
150
Featured
See All Featured
WCS-LA-2024
lcolladotor
0
840
Darren the Foodie - Storyboard
khoart
PRO
4
4k
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
520
Faster Mobile Websites
deanohume
310
32k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
320
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
550
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
210
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
470
WENDY [Excerpt]
tessaabrams
14
40k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
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 ʑࣝܦݧΛͱʹΞοϓσʔτ͍ͯ͘͠