【Laravel】リソースコントローラーでサクッとCRUDを作成する
この記事について
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が生成されました。
<?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
にルートを定義します。
<?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つは置いといて)ちゃんとルートが定義されてますね!
実際に呼び出せるかも確認してみます。
public function index()
{
exit("hoge");
}
index
が呼び出されてますね!
コマンドの中身を見てみる
これだけだと、あっさりし過ぎているのでもうちょっと調べてみます🧐
php artisan make:controller
は、↓の場所で定義されているようです。
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の型みたいな感じですかね…)を使用するみたいです🤔
<?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テンプレートを返すルートを除外したり、任意のアクションだけ生成するようにできるなど、色々できるようです。
便利…なんでしょうか🧐
Discussion