Laravelのルーティングとミドルウェアの使い方

はじめに

Webアプリケーションの開発において、ルーティングとミドルウェアは非常に重要な要素です。ルーティングはユーザーのリクエストを適切なコントローラーアクションに振り分け、ミドルウェアはそれらのリクエストを処理する前後に特定の処理を実行します。Laravelはこれらのメカニズムをエレガントかつパワフルに実装しています。

この記事では、Laravelにおけるルーティングとミドルウェアの基本的な使い方から、より高度なテクニックまでを紹介します。

ルーティングの基本

Laravelのルーティングは、主にroutes/web.phproutes/api.phpファイルで定義します。

基本的なルーティング

// routes/web.php
use Illuminate\Support\Facades\Route;

// GETリクエスト
Route::get('/hello', function () {
    return 'Hello World';
});

// POSTリクエスト
Route::post('/submit', function () {
    // フォーム送信処理
});

// その他のHTTPメソッド
Route::put('/update/{id}', function ($id) {
    // 更新処理
});

Route::delete('/delete/{id}', function ($id) {
    // 削除処理
});

コントローラーを使用したルーティング

// routes/web.php
use App\Http\Controllers\UserController;

// 単一アクション
Route::get('/users', [UserController::class, 'index']);

// リソースコントローラー(CRUD操作)
Route::resource('posts', PostController::class);

// 特定のアクションだけを指定
Route::resource('photos', PhotoController::class)->only([
    'index', 'show'
]);

// 特定のアクションを除外
Route::resource('comments', CommentController::class)->except([
    'create', 'store', 'update', 'destroy'
]);

ルートパラメータ

// 必須パラメータ
Route::get('/user/{id}', function ($id) {
    return 'User '.$id;
});

// オプションパラメータ
Route::get('/user/{name?}', function ($name = 'Guest') {
    return 'Hello '.$name;
});

// 正規表現制約
Route::get('/user/{id}', function ($id) {
    // IDが数値の場合のみマッチ
})->where('id', '[0-9]+');

// 複数のパラメータ制約
Route::get('/post/{id}/{slug}', function ($id, $slug) {
    // 処理
})->where([
    'id' => '[0-9]+',
    'slug' => '[A-Za-z0-9\-]+'
]);

名前付きルート

Route::get('/user/profile', function () {
    // 処理
})->name('profile');

// 名前付きルートの使用例
$url = route('profile');
return redirect()->route('profile');

ルートグループ

// プレフィックスを共有するルートグループ
Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        // /admin/users にマッチ
    });
    Route::get('/posts', function () {
        // /admin/posts にマッチ
    });
});

// ミドルウェアを共有するルートグループ
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        // 認証ユーザーのみアクセス可能
    });
    Route::get('/settings', function () {
        // 認証ユーザーのみアクセス可能
    });
});

// 名前空間を共有するルートグループ
Route::namespace('Admin')->group(function () {
    // App\Http\Controllers\Admin 名前空間のコントローラー
});

// 複数の属性を組み合わせたグループ
Route::prefix('admin')
     ->middleware(['auth', 'admin'])
     ->name('admin.')
     ->group(function () {
        Route::get('/dashboard', function () {
            // admin.dashboard という名前のルート
        })->name('dashboard');
     });

ミドルウェアの基本

ミドルウェアは、HTTPリクエストをフィルタリングするメカニズムです。例えば、認証や権限チェックなどに利用されます。

ミドルウェアの作成

新しいミドルウェアを作成するには、以下のArtisanコマンドを使用します:

php artisan make:middleware CheckAge

これにより、app/Http/Middleware/CheckAge.phpファイルが生成されます。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CheckAge
{
    /**
     * リクエストの処理
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if ($request->age < 18) {
            return redirect('home');
        }

        return $next($request);
    }
}

ミドルウェアの登録

ミドルウェアを使用するには、app/Http/Kernel.phpファイルに登録する必要があります。

// app/Http/Kernel.php

// グローバルミドルウェア(全リクエストに適用)
protected $middleware = [
    \App\Http\Middleware\TrustProxies::class,
    \Fruitcake\Cors\HandleCors::class,
    \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];

// ルートミドルウェア(特定のルートに適用)
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    'checkage' => \App\Http\Middleware\CheckAge::class, // 追加したミドルウェア
];

ミドルウェアの適用

// 単一ルートにミドルウェアを適用
Route::get('/profile', function () {
    // 処理
})->middleware('auth');

// 複数のミドルウェアを適用
Route::get('/admin/profile', function () {
    // 処理
})->middleware(['auth', 'admin']);

// ルートグループにミドルウェアを適用
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        // 処理
    });
    Route::get('/settings', function () {
        // 処理
    });
});

// コントローラーのコンストラクターでミドルウェアを適用
class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}

ミドルウェアの高度な使い方

パラメータ付きミドルウェア

パラメータを受け取るミドルウェアも作成できます。

// app/Http/Middleware/RoleCheck.php
public function handle($request, Closure $next, $role)
{
    if (!$request->user()->hasRole($role)) {
        return redirect('home');
    }

    return $next($request);
}

// 使用方法
Route::get('/admin', function () {
    // 処理
})->middleware('role:admin');

// 複数のパラメータ
Route::get('/admin/posts', function () {
    // 処理
})->middleware('role:admin,editor');

Terminable ミドルウェア

レスポンスがブラウザに送信された後に実行される処理を定義できます。

<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        // レスポンスの処理

        return $response;
    }

    public function terminate($request, $response)
    {
        // レスポンスがブラウザに送信された後に実行
        // ログ記録などに便利
    }
}

実践的な例

認証済みユーザーのみアクセス可能なページ

// routes/web.php
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        return view('dashboard');
    });
    
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
});

管理者専用セクション

// app/Http/Middleware/AdminMiddleware.php
public function handle(Request $request, Closure $next)
{
    if (!$request->user() || !$request->user()->isAdmin()) {
        abort(403, '権限がありません');
    }
    
    return $next($request);
}

// routes/web.php
Route::prefix('admin')
     ->middleware(['auth', 'admin'])
     ->name('admin.')
     ->group(function () {
        Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
        Route::resource('users', AdminUserController::class);
        Route::resource('posts', AdminPostController::class);
     });

APIレート制限

// routes/api.php
Route::middleware('auth:api')->group(function () {
    Route::middleware('throttle:60,1')->group(function () {
        Route::get('/user', function (Request $request) {
            return $request->user();
        });
    });
    
    // 特定のエンドポイントには異なるレート制限を適用
    Route::middleware('throttle:5,1')->group(function () {
        Route::post('/sensitive-operation', [SensitiveController::class, 'process']);
    });
});

ルーティングとミドルウェアのベストプラクティス

1. ルートをファイルに分割する

アプリケーションが大きくなる場合、ルートを論理的なグループに分割して別々のファイルに保存することで管理しやすくなります。

// routes/admin.php を作成
// app/Providers/RouteServiceProvider.php で読み込む
protected function mapAdminRoutes()
{
    Route::prefix('admin')
         ->middleware(['web', 'auth', 'admin'])
         ->namespace($this->namespace.'\Admin')
         ->group(base_path('routes/admin.php'));
}

2. ミドルウェアグループの定義

頻繁に使用するミドルウェアの組み合わせは、Kernelクラスでグループとして定義します。

// app/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // ...
    ],
    
    'api' => [
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
    
    'admin' => [
        'auth',
        'admin',
        'log',
    ],
];

// 使用方法
Route::middleware('admin')->group(function () {
    // 処理
});

3. ルートモデルバインディングの活用

// 暗黙的なバインディング
Route::get('/users/{user}', function (App\Models\User $user) {
    return $user->email;
});

// カスタムキーによるバインディング(IDではなくスラグを使用)
// app/Models/Post.php
public function getRouteKeyName()
{
    return 'slug';
}

// 明示的なバインディング
// app/Providers/RouteServiceProvider.php
public function boot()
{
    parent::boot();
    
    Route::bind('user', function ($value) {
        return App\Models\User::where('username', $value)->firstOrFail();
    });
}

まとめ

Laravelのルーティングとミドルウェアは、Webアプリケーションの構築において強力なツールです。適切に使用することで、コードの構造化、セキュリティの向上、そして開発効率の向上が実現できます。

この記事で紹介した基本的な使い方から高度なテクニックまでを活用して、より堅牢で保守性の高いLaravelアプリケーションを開発していきましょう。

ルーティングでリクエストを正確に適切なコントローラーに導き、ミドルウェアで必要なチェックや処理を施すことで、あなたのLaravelアプリケーションはより強固なものになります。

コメント

タイトルとURLをコピーしました