🐿️

【Laravel】リソースコントローラーでサクッとCRUDを作成する

2024/01/24に公開

この記事について

Laravelのリソースコントローラーをちょっと触ってみた記事です。
何か改善点などあればご指摘ください 🙏

リソースコントローラーとは

アプリケーション内の各Eloquentモデルを「リソース」と考える場合、通常、アプリケーション内の各リソースに対して同じ一連のアクションを実行します。たとえば、アプリケーションにPhotoモデルとMovieモデルが含まれているとします。ユーザーはこれらのリソースを作成、読み取り、更新、または削除できるでしょう。
このようなコモン・ケースのため、Laravelリソースルーティングは、通常の作成、読み取り、更新、および削除("CRUD")ルートを1行のコードでコントローラに割り当てます。
https://readouble.com/laravel/10.x/ja/controllers.html

CRUD処理へのルーティングを簡単に作成してくれるもののようです🤔

実践

環境構築

Laravelの環境はLaravel Sailで構築します。
with=mysqlと指定していますが、何も指定しないとRedisやmeilisearchなど諸々追加されてしまうので)
curl -s "https://laravel.build/example-app?with=mysql" | bash

./vendor/bin/sail upでコンテナを起動します。

コントローラー作成

コントローラーの作成時に--resourceを指定すると、アクションがすでに定義されているコントローラーが作成されます。
今回は、モデルのインスタンスを自動で取得してきて欲しいので、--modelも指定します😺

# php artisan make:controller TestController --model=Test --resource

 ┌ A App\Models\Test model does not exist. Do you want to generate it? ┐
 │ ● Yes / ○ No                                                        │
 └─────────────────────────────────────────────────────────────────────┘

INFO  Model [app/Models/Test.php] created successfully.  

INFO  Controller [app/Http/Controllers/TestController.php] created successfully.  

Modelを作成していない場合は作成してくれるようです。

↓のようなControllerが生成されました。

app/Http/Controller/TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\Test;
use Illuminate\Http\Request;

class TestController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(Test $test)
    {
        //
    }

他にもedit, update, destroyが作成されていました。

ルーティング定義

routes/web.phpにルートを定義します。

routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TestController;

Route::resource('test', TestController::class);

確認

php artisan route:listで定義されているルートを確認してみます😺

# php artisan route:list

  POST            _ignition/execute-solution .................. ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController
  GET|HEAD        _ignition/health-check .............................. ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
  POST            _ignition/update-config ........................... ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
  GET|HEAD        api/user .................................................................................................................. 
  GET|HEAD        sanctum/csrf-cookie ..................................... sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show
  GET|HEAD        test .................................................................................... test.index › TestController@index
  POST            test .................................................................................... test.store › TestController@store
  GET|HEAD        test/create ........................................................................... test.create › TestController@create
  GET|HEAD        test/{test} ............................................................................... test.show › TestController@show
  PUT|PATCH       test/{test} ........................................................................... test.update › TestController@update
  DELETE          test/{test} ......................................................................... test.destroy › TestController@destroy
  GET|HEAD        test/{test}/edit .......................................................................... test.edit › TestController@edit

                                                                                                                          Showing [12] routes

(上の5つは置いといて)ちゃんとルートが定義されてますね!

実際に呼び出せるかも確認してみます。

app/Http/Controller/TestController.php
public function index()
    {
        exit("hoge");
    }

アクセスして確認

indexが呼び出されてますね!

コマンドの中身を見てみる

これだけだと、あっさりし過ぎているのでもうちょっと調べてみます🧐

php artisan make:controllerは、↓の場所で定義されているようです。

vendor/laravel/framework/src/Illuminate/Routing/Console/ControllerMakeCommand.php

今回実行したオプションと関係がありそうな箇所を見てみます👀

/vendor/laravel/framework/src/Illuminate/Routing/Console/ControllerMakeCommand.php
protected function getStub()
    {
        $stub = null;

        if ($type = $this->option('type')) {
            $stub = "/stubs/controller.{$type}.stub";
        } elseif ($this->option('parent')) {
            $stub = $this->option('singleton')
                        ? '/stubs/controller.nested.singleton.stub'
                        : '/stubs/controller.nested.stub';
        } elseif ($this->option('model')) {
            $stub = '/stubs/controller.model.stub';
        } elseif ($this->option('invokable')) {
            $stub = '/stubs/controller.invokable.stub';
        } elseif ($this->option('singleton')) {
            $stub = '/stubs/controller.singleton.stub';
        } elseif ($this->option('resource')) {
            $stub = '/stubs/controller.stub';
        }
        (省略)
        return $this->resolveStubPath($stub);
    }

modelのところの条件式がtrueになるので、'/stubs/controller.model.stub';スタブ(今回の文脈だと、生成するControllerの型みたいな感じですかね…)を使用するみたいです🤔

vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.model.stub
<?php

namespace {{ namespace }};

use {{ namespacedModel }};
use {{ rootNamespace }}Http\Controllers\Controller;
use {{ namespacedRequests }}

class {{ class }} extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        //
    }

    (create, storeは省略)

    /**
     * Display the specified resource.
     */
    public function show({{ model }} ${{ modelVariable }})
    {
        //
    }

今回は、モデルと紐づける--modelを使用したため、showの引数にModelが指定されていますね😺

これを元に、指定されたControllerやModelの名前に置き換えてControllerが作成される感じでしょうか。

何も指定していないと、最低限の記述だけのcontroller.plain.stubが使用されるみたいです。

おわりに

他にも、API用にHTMLテンプレートを返すルートを除外したり、任意のアクションだけ生成するようにできるなど、色々できるようです。
便利…なんでしょうか🧐

GitHubで編集を提案

Discussion