こんにちは、かつコーチです。
前回はRoute設計の整理術を解説しました。
ここまでの記事では、ルートの処理をクロージャ(function () {...})にそのまま書いてきました。
小さなアプリならそれでも動きますが、処理が増えてくると routes/web.php がどんどん長くなり、見通しが悪くなります。
そこで登場するのがControllerです。
今回は、Controllerの役割と、Artisanコマンドを使った作り方を解説します。
Controllerとは?
処理をルートから切り離す役割
Controllerとは、リクエストに対する具体的な処理をまとめて書くためのクラスです。
PHP編でMVCの考え方に触れましたが、Laravelの世界でも基本の考え方は同じです。
- Route:どのURLをどの処理につなげるかの「案内係」
- Controller:実際の処理内容を書く「実行係」
- Model:データベースとのやり取りを担当(次回以降で解説)
- View(Blade):画面の見た目を担当
ルートに直接処理を書き続けると、案内係と実行係の役割が混ざってしまい、コードの見通しが悪くなります。
Controllerを使うことで、「このURLはこのControllerのこのメソッドが処理する」という形に整理でき、規模が大きくなっても対応しやすくなります。
クロージャで書く場合との比較
まずは、クロージャで書いていた処理をControllerに移す前後を比べてみましょう。
❌ Before:ルートに直接処理を書く(規模が大きくなると厳しい)
<?php
// routes/web.php
use Illuminate\Support\Facades\Route;
Route::get('/articles', function () {
// 本来はここに記事一覧を取得する処理や、
// ビューを組み立てる処理が何行も続く
return view('articles.index');
});
Route::get('/articles/{id}', function ($id) {
// ここにも記事詳細を取得する処理が続く
return view('articles.show', ['id' => $id]);
});
ルートの数だけクロージャが並び、処理内容が長くなるほど routes/web.php が読みにくくなります。
✅ After:Controllerに処理をまとめる
<?php
// routes/web.php
use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;
Route::get('/articles', [ArticleController::class, 'index'])->name('articles.index');
Route::get('/articles/{id}', [ArticleController::class, 'show'])->name('articles.show');
<?php
// app/Http/Controllers/ArticleController.php
namespace App\Http\Controllers;
class ArticleController extends Controller
{
public function index()
{
return view('articles.index');
}
public function show($id)
{
return view('articles.show', ['id' => $id]);
}
}
ルート側は「どのURLがどのメソッドを呼ぶか」だけが書かれたシンプルな一覧になり、具体的な処理内容はControllerクラスの中に整理されます。
[ArticleController::class, 'index'] という書き方は、「ArticleControllerクラスのindexメソッドを呼び出す」という意味です。
Controllerの作り方
Artisanコマンドで生成する
Controllerは手書きでファイルを作ることもできますが、Artisanコマンドを使うのが基本です。
php artisan make:controller ArticleController
このコマンドを実行すると、app/Http/Controllers/ArticleController.php が自動生成されます。
<?php
namespace App\Http\Controllers;
class ArticleController extends Controller
{
//
}
クラス名の末尾に Controller をつけるのが命名の慣習で、Artisanコマンドでも自動的にこの形で生成されます。
自分で空のクラスを1から書くより、タイプミスも減って確実です。
リソースコントローラで一気に生成する
前回の記事で紹介したRESTfulな設計(index / create / store / show / edit / update / destroy)に沿うなら、--resource オプションを使うと、必要なメソッドがすべて揃った状態で生成できます。
php artisan make:controller ArticleController --resource
生成される内容は次のようになります。
<?php
namespace App\Http\Controllers;
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
public function index()
{
//
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show(string $id)
{
//
}
public function edit(string $id)
{
//
}
public function update(Request $request, string $id)
{
//
}
public function destroy(string $id)
{
//
}
}
一覧・作成・詳細・編集・更新・削除という、CRUD操作に必要なメソッドが最初からひな形として揃っています。
私は最初、このオプションの存在を知らずに7つのメソッドを1つずつ手打ちしていましたが、--resource を知ってからは生成の手間がほぼゼロになりました。
リソースルートとセットで使う
Route::resourceで一括登録
リソースコントローラを作ったら、ルート側も Route::resource で一括登録できます。
<?php
// routes/web.php
use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;
Route::resource('articles', ArticleController::class);
このたった1行で、前回の記事で紹介した7つのRESTfulなルートがまとめて登録されます。
登録内容を確認したいときは、前回学んだ route:list コマンドが役立ちます。
php artisan route:list --path=articles
--path オプションでURLを絞り込むと、articles に関するルートだけが一覧表示され、7つのルートが自動生成されていることを確認できます。
つまずきやすいポイント:メソッド名のスペルミス
エラーメッセージの読み方
Controllerを使い始めたころ、私がよくやっていたミスがメソッド名のタイプミスです。
❌ Before:ルート側とController側でメソッド名が食い違う
<?php
// routes/web.php
Route::get('/articles', [ArticleController::class, 'indexx']); // タイポ
<?php
// app/Http/Controllers/ArticleController.php
public function index()
{
return view('articles.index');
}
このまま /articles にアクセスすると、次のようなエラーが表示されます。
Error: Call to undefined method App\Http\Controllers\ArticleController::indexx()
「indexx というメソッドは存在しません」という意味のエラーで、原因はルート側のスペルミスです。
✅ After:メソッド名を正しく揃える
<?php
// routes/web.php
Route::get('/articles', [ArticleController::class, 'index']); // 正しいメソッド名
このエラーが出たら、まず疑うべきはControllerの中身ではなく、ルート側で指定しているメソッド名のスペルです。
エラーメッセージに Call to undefined method と表示された場合は、クラス名かメソッド名のどちらかが間違っている、とほぼ確定で考えて大丈夫です。
私はこのエラーが出るたびにController側のロジックを疑って時間を無駄にしていたので、まずルート側のスペルを確認する習慣をつけてから、原因特定がぐっと早くなりました。
まとめ
この記事のポイント
- Controllerは、ルートから処理内容を切り離して整理するためのクラス
php artisan make:controllerでControllerのひな形を生成できる--resourceオプションを使うと、CRUD操作に必要な7つのメソッドが最初から揃うRoute::resourceを使うと、RESTfulな7つのルートを1行で登録できるCall to undefined methodエラーは、ルート側とController側のメソッド名の不一致を疑う
次に読むべき記事
Controllerが書けるようになったら、次は認証チェックなどの共通処理を挟む仕組み、Middlewareについて解説します。
→ 次の記事:Middlewareとは?認証チェックなどの共通処理を挟む仕組み