今回はリソースコントローラのテンプレートに合わせてリファクタリングした過程をご紹介します。
Laravelで簡単なブログアプリを作った後、Laravel Breezeを適用しようとして、routes/web.phpが上書きされてしまいました。
改めて、URIとHTTPメソッドの組み合わせごとに、コントローラのメソッドを割り当て、ルート名を付ける作業が面倒に思いました。
そこで、モデル作成のコマンドでリソースコントローラのオプションがあるくらいだから、ルーティングもテンプレート的なものを利用してもっと効率的に実装できるのでは?と考え、調べてみるとありました。
調べて実践した内容をご紹介します。
リソースコントローラへのリファクタリング
リソースコントローラとは
参考:Laravel 10.x コントローラ
上記サイトを参考に自分なりの言葉でまとめると、下記特徴を持つコントローラです。
- CRUDと呼ばれるリソースの作成、読み取り、更新、削除のいずれか、またはすべてを行う
- Artisanコマンドのmake:controller、make:modelで–resourceオプションを指定して手軽に作成できる
- URIやメソッド名が機械的に決まるため命名に悩まなくて済む、かつ、ブレない
修正するコード
今回修正するコードは下記記事で作成したコードになります。
過去記事関係なくリソースコントローラに変更する時の要所だけ見たい人もbefore/afterのコードを記載するので、参考になるかと思います。
修正箇所と内容
リソースコントローラを使うにあたり、下記コードを修正します。
| No. | 修正ファイル | 修正内容 |
|---|---|---|
| 1 | routes/web.php | 各ルートの定義をRoute::resourceにまとめる |
| 2 | app/Http/Controllers/ArticleController.php | リソースコントローラに合った引数、処理に修正 |
| 3 | resources/view/index.blade.php | ルートの変更に伴い、リンクの修正 |
ルーティングの修正(routes/web.php)
下記before/afterのようにコードを修正します。
~略~
Route::controller(ArticleController::class)->group(function (){
Route::get('/articles', 'index')->name('articles.index');
Route::get('/articles/new', 'create')->name('articles.create');
Route::post('/articles', 'store')->name('articles.store');
Route::get('/articles/{id}', 'show')->name('articles.show');
Route::get('/articles/{id}/edit', 'edit')->name('articles.edit');
Route::put('/articles/{id}', 'update')->name('articles.update');
Route::delete('/articles/{id}', 'destroy')->name('articles.destroy');
});
Route::redirect('/','/articles');Route::resource('articles', ArticleController::class);
Route::redirect('/','/articles');9行かかっていたコードが1行で済むようになりました。
どのコントローラでどのテーブルを扱っているか、わかりやすくもなりますね!
ただし、この修正だけでブログサイトにアクセスすると下記のようなエラーが発生します。
Missing required parameter for [Route: articles.show] [URI: articles/{article}] [Missing parameter: article].これは、beforeで{id}とした箇所がリソースコントローラの制約に違反しているためです。
リソースコントローラでは、下記表のようにルート名やコントローラのメソッド名が決まるため、それに合わせる必要があります。
そのため、コントローラとビューも修正します。
| No. | HTTPメソッド | URI | メソッド名 | ルート名 |
|---|---|---|---|---|
| 1 | GET | /articles | index | articles.index |
| 2 | GET | /articles/create | create | articles.create |
| 3 | POST | /articles | store | articles.store |
| 4 | GET | /articles/{article} | show | articles.show |
| 5 | GET | /articles/{article}/edit | edit | articles.edit |
| 6 | PUT/PATCH | /articles/{articles} | update | articles.update |
| 7 | DELETE | /articles/{articles} | destroy | articles.destroy |
コントローラの修正(app/Http/Controllers/ArticleController.php)
下記before/afterのようにコードを修正します。
~略~
/**
* Display the specified resource.
* Article $articleを$idに変更
*/
public function show($id)
{
$article = Article::find($id);
return view('show',['article' => $article]);
}
~略~
public function edit($id)
{
$article = Article::find($id);
$categories = Category::all();
return view('edit',['article' => $article, 'categories' => $categories]);
}
~略~
public function update(Request $request, $id)
{
Article::find($id)->update([
'title' => request('title'),
'content' => request('content'),
'category_id' => request('category_id'),
]);
return redirect('articles/'.$id);
}
~略~
public function destroy($id)
{
$article = Article::find($id);
$article->delete();
return redirect('/articles');
}~略~
/**
* Display the specified resource.
* $idをArticle $articleに戻す
*/
public function show(Article $article)
{
return view('show',['article' => $article]);
}
~略~
public function edit(Article $article)
{
$categories = Category::all();
return view('edit',['article' => $article, 'categories' => $categories]);
}
~略~
public function update(Request $request, Article $article)
{
$article->update([
'title' => request('title'),
'content' => request('content'),
'category_id' => request('category_id'),
]);
return redirect('articles/'.$article->id);
}Article::find($id)としていた処理が不要になり、引数のarticleをそのまま使うだけになりました。
これはLaravelが、パスパラメータ(URIで{}で囲まれた部分)とコントローラメソッドの型名が一致する場合、自動でパスパラメータに紐づく値をデータベースから取得してくれるためです。
resoures/views/index.blade.php
ビューでルート名を使用して、リンクを作成していたため、このファイルも修正が必要です。
<!--修正前-->
<td><a href={{ route('articles.show', ['id' => $article->id]) }}>{{ $article->title }}</a></td>
<!--修正後-->
<td><a href={{ route('articles.show', ['article' => $article]) }}>{{ $article->title }}</a></td>また、URIをハードコードしている他の個所も修正しておくと良いかもしれません。
感想
ブログアプリ作成時に各URIを1つずつ実装することもLaravelを理解する上で良かったのですが、リソースコントローラを使うとかなりすっきりしたコードになることがわかりました。
これからはリソースコントローラを使い、それで足りない場合は本当に1つのコントローラで実装する必要があるのか、2つに分けた方が良いのではないか、を考えて開発していこうと思いました。




コメント