Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Finding Laravel Best Practices in 2018

nunulk
September 08, 2018

Finding Laravel Best Practices in 2018

nunulk

September 08, 2018
Tweet

More Decks by nunulk

Other Decks in Technology

Transcript

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

    nunulk

    View Slide

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

    View Slide

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

    View Slide

  4. ࣗݾ঺հ
    $I->am('nunulk(͵͵Δ͘)')

    ->workAs('a freelance programmer')
    ->tackleComplexityOfSoftware()
    ->with([
    'Laravel',

    ‘Vue.js’,
    ]);

    View Slide

  5. DogHuggy

    View Slide

  6. SCOUTER

    View Slide

  7. Laravelͷಛ௕

    View Slide

  8. Laravelͷಛ௕

    View Slide

  9. Laravelͷಛ௕

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. LaravelͷΞʔΩςΫνϟ֓ཁ

    View Slide

  14. Router
    Middleware
    Request
    Kernel
    Controller
    Response
    Model
    Event
    Job
    View
    Resource

    View Slide

  15. Routing

    Route::get('/', function () {
    return view('welcome');
    });
    Auth::routes();
    Route::get('/home', '[email protected]')->name('home');

    View Slide

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

    View Slide

  17. 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',
    ];
    }

    View Slide

  18. 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);
    }

    View Slide

  19. Event
    public function create(CreateTaskRequest $request)
    {
    $task = new Task();

    // (snip)

    $task->save();

    TaskCreated::dispatch($task);

    return new JsonResponse($task, Response::HTTP_CREATED);
    }

    View Slide

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

    View Slide

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

    View Slide

  22. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  30. 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',
    ];
    }

    View Slide

  31. 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',
    ];
    }

    View Slide

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

    View Slide

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

    View Slide

  34. 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);
    }

    View Slide

  35. Controller (after)
    public function create(CreateTaskRequest $request)
    {
    $task = $request->makeTask();
    $task->save();

    return response()->json($task, Response::HTTP_CREATED);
    }

    View Slide

  36. Controller (after)
    class CreateTaskRequest extends FormRequest
    {
    public function makeTask(): Task
    {
    return new Task([

    ‘created_by' => $this->user()->id

    + $this->validated()

    ]);
    }
    }

    View Slide

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

    View Slide

  38. Controller (after)
    public function show(Task $task)
    {

    // snip
    return $task;
    }

    View Slide

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

    View Slide

  40. &WFOU+PC/PUJpDBUJPO

    ͷ࢖͍෼͚ͱ໋໊

    View Slide

  41. Event/Job/Notification
    public function create(CreateTaskRequest $request)
    {
    $task = $request->makeTask();

    $task->save();

    TaskCreated::dispatch($task);

    return response()->json($task, Response::HTTP_CREATED);
    }

    View Slide

  42. 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));
    }

    View Slide

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

    View Slide

  44. 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));
    }
    }

    View Slide

  45. Event/Job/Notification
    w ॲཧ్͕தͰࣦഊ͢Δ͜ͱΛߟྀ͠ɺಉҰϦεφͰෳ਺ͷ
    ॲཧΛͤͣɺϦεφΛ෼͚Δ
    w &WFOU͸$POUSPMMFSʹରԠ͢ΔΑ͏ʹ໋໊͢Δʢݱࡏ෼ࢺ
    ܕͰऴΘΔΑ͏ʹʣ

    ྫʣ5BTL$SFBUF$POUSPMMFS5BTL$SFBUFE
    w +PC͸ৼΔ෣͍͕ࣝผ͢ΔΑ͏ʹ໋໊͢Δʢಈࢺ͔Β࢝Ί
    Δʣ

    ྫʣ6QEBUF5BTL"HHSFHBUFT
    w /PUJpDBUJPO͸&WFOUͱಉ໋໊͡

    View Slide

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

    View Slide

  47. 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();
    }

    View Slide

  48. Model (after)

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

    }
    }


    View Slide

  49. 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();
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  53. 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"
    }

    View Slide

  54. 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();
    }

    View Slide

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

    View Slide

  56. %*αʔϏείϯςφ

    View Slide

  57. DI (before)

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

    }
    }


    View Slide

  58. DI (after)

    class ExternalItsController extends Controller
    {
    private $issueTracker;
    public function __construct(IssueTracker $issueTracker)
    {
    $this->issueTracker = $issueTracker;
    }
    public function index()
    {

    $issueTracker = app(IssueTracker::class);
    // snip

    }
    }


    View Slide

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

    View Slide

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

    View Slide

  61. ͦͷଞ

    View Slide

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

    View Slide

  63. ·ͱΊ

    View Slide

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

    View Slide