【Laravel】ルーティングをまとめる方法

どーも!

たかぽんです!

今回はLaravelのルーティングをする際にいい感じにまとめる方法を調べていきます...! 

ルーティングをまとめる方法!

今回はLaravelでルーティングを設定することがあると思います。

その際にどんな方法でまとめればいいのか?

この際に今一度確認をして、一通りまとめておこうと思います!

ルーティングをまとめるとは・・・

さて、まずはルーティングをまとめる...?というのはどういうことか説明をしておきます。

Laravelでのルーティングは、Webサービスの場合に、ユーザーがブラウザからアクセスをする際、"http://localhost/test"というパスにアクセスをした場合に、Laavelで作成した"welcome"viewを表示する...!

といった、アクセス時のURLと表示するviewや処理の対応を設定するのがルーティングになります。

上記を簡単にコードにすると...

Route::get('/test', function () {
    return view('welcome');
});

こんな感じです。

Laravelではデフォルトだと、"routes/web.php"に記載することになっています。

詳しい説明は割愛しますね。

そういったルーティングを設定する場合、例えば"http://localhost/test/hoge"といったURL、"http://localhost/test/huga"といったURLがあったとします。

このルーティングを作る場合...

Route::get('/test/hoge', function () {
    return view('welcome');
});

Route::get('/test/huga', function () {
    return view('welcome');
});

このような感じになります。(本来は返すviewを変えたりしますが、今回はそこは割愛します...!)

この場合、都度都度getで別のルートを定義していく...といったこともできますが、ルートに共通部分(今回は"test")があれば、それをまとめてしまいたい...!

というのが今回のやりたいことになります...!

まとめる前の状態

まず、ルーティングをまとめる前の状況を置いておきます。

// viewを直接返す場合の例
Route::get('/test/takapon/hoge', function () {
    return view('takapon');
});
Route::get('/test/takapon/huga', function () {
    return view('takapon');
});
Route::get('/test/laravel', function () {
    return view('laravel');
});

// Controllerを呼び出す場合の例 (laravel8.xの記述)
Route::get('/test/takapon/hoge',[TakaponController::class, 'index']);
Route::get('/test/takapon/huga',[TakaponController::class, 'index']);
Route::get('/test/laravel',[TakaponController::class, 'index']);

簡単に説明しておくと、viewをそのまま返すルーティングと、Controllerのアクションを呼び出すような書き方ですね。

それぞれ3つのルーティングがあり、そのうち、"test"は全てに共通、"test/takapon"は一部で共通している...といった状況です。

Controller, view側の処理は割愛します...!(今回はテストのため、routingに限らず同じview, actionにしちゃってます...w)

では、それぞれの場合でどんなふうになるのか?を書いていきます。

prefixを用いてまとめる方法

まずはprefix(先頭部分)でまとめる方法です。

prefixメソッドを使うことで、前方で一致している部分があればまとめることが可能です。

// viewを直接返す場合の例
Route::prefix('test')->group(function () {
    Route::prefix('takapon')->group(function () {
        Route::get('hoge', function () {
            return view('welcome');
        });
        Route::get('huga', function () {
            return view('welcome');
        });
    });
    Route::get('laravel', function () {
        return view('welcome');
    });
});

// 繋げての書き方も可能(ただし、"test/laravel"のルートは別途定義が必要になる)
Route::prefix('test/takapon')->group(function () {
    Route::get('hoge', function () {
        return view('welcome');
    });
    Route::get('huga', function () {
        return view('welcome');
    });
});

// Controllerを呼び出す場合の例
Route::prefix('test')->group(function () {
    Route::prefix('takapon')->group(function () {
        Route::get('hoge',[TakaponController::class, 'index']);
        Route::get('huga',[TakaponController::class, 'index']);
    });
    Route::get('laravel',[TakaponController::class, 'index']);
});

// 繋げての書き方も可能(ただし、"test/laravel"のルートは別途定義が必要になる)
Route::prefix('test/takapon')->group(function () {
    Route::get('hoge',[TakaponController::class, 'index']);
    Route::get('huga',[TakaponController::class, 'index']);
});

さて、簡単に補足しておくと、prefixというのは異パン的に先頭部分を意味します。

今回はURIのprefix...という意味合いになるため、例えば....

"http://localhost/test/hoge"

という文字があった場合、"http://localhost"まではアプリの設定できめるので、除外し、その後の"/test/hoge"がprefixになり得ます。

なり得ます...というのは、"/test"をprefixと見ることも可能ですし、"/test/hoge"をprefixと見ることも可能...という意味合いを含んでます。(先頭からある一定範囲までのことをprefixと呼ぶことがあります)

そのため、先頭から"test"の分をprefixと見た場合...

以下のようにすれば設定が可能です。(指定時に、最初の"/"は省略可能です)

Route::prefix('test')->group(function () {
  // 後続のルート情報を記載
}

さらに細かく、"/test/hoge"をprefixとした場合、以下のようにも設定が可能です。

Route::prefix('test/hoge')->group(function () {
  // 後続のルート情報を記載
}

ただし...!

prefixとして、"test/hoge"で括った場合、仮に、test部分のみ共通する、他の"test/huga"等があったとしたら、別で括ってあげる必要が有ります。

そのため、prefixの場合は、prefixで最初に"test"を括り、その中で再度"hoge"等で括ってあげる形がおすすめです。

(特定のURIを直接指定するか、手前から順々に指定していくか...といった違いですね...!)

今後、途中のURIから派生することが無いと言い切れるのであれば、直接指定しても良いと思いますが...、大抵は細かく指定してく方が良くなるかと思います...!

最後に、Laravelの公式資料の翻訳ページを添付しておきます。

是非一読してみてください..!

ルートのnameも括る場合

さて、ルートの括り方はわかったので、次はnameも括ってみます。

ルートに名前をつけることができるのですが、その場合にどうすればいいのか?についてみていきたいと思います。

Route::prefix('test')->name('test.')->group(function () {
    Route::prefix('takapon')->name('takapon.')->group(function () {
        Route::get('hoge', function () {
            return view('welcome');
        })->name('hoge');
        Route::get('huga', function () {
            return view('welcome');
        })->name('huga');
    });
    Route::get('laravel', function () {
        return view('welcome');
    })->name('laravel');
});

まずはview呼び出しを直接行なってるパターンでみていきます。

ご覧いただくとわかりますが、nameメソッドで、名前の先頭には"test."っていう名前をつけるよ!

といった指定をしています。

こうすることによって、そのgroup内で書かれているルートには全てその効果が適応されるわけですね...!

一応、"php artisan route:list"コマンドで確認をしておきます。

ちゃんと、

+--------+----------+-------------------+-------------------+---------+------------+
| Domain | Method   | URI               | Name              | Action  | Middleware |
+--------+----------+-------------------+-------------------+---------+------------+
|        | GET|HEAD | test/laravel      | test.laravel      | Closure | web        |
|        | GET|HEAD | test/takapon/hoge | test.takapon.hoge | Closure | web        |
|        | GET|HEAD | test/takapon/huga | test.takapon.huga | Closure | web        |
+--------+----------+-------------------+-------------------+---------+------------+

URIとNameがちゃんと対応していますね...!

理想はURIとNameは一致させることがベストになるかなと思います。

そのため、nameをつける場合は、同じくnameも括ってあげた方が管理がしやすいかと思います。

では、次に、コントローラを呼び出しているパターンもみておきます。(といっても、対して変わりませんが...!)

Route::prefix('test')->name('test.')->group(function () {
    Route::prefix('takapon')->name('takapon.')->group(function () {
        Route::get('hoge',[TakaponController::class, 'index'])->name('hoge');
        Route::get('huga',[TakaponController::class, 'index'])->name('huga');
    });
    Route::get('laravel',[TakaponController::class, 'index'])->name('laravel');
});

同じくnameメソッドで括ってあげればいい感じですね...!

確認しておくと、ちゃんとNameもついています。

+--------+----------+-------------------+-------------------+----------------------------------------------+------------+
| Domain | Method   | URI               | Name              | Action                                       | Middleware |
+--------+----------+-------------------+-------------------+----------------------------------------------+------------+
|        | GET|HEAD | test/laravel      | test.laravel      | App\Http\Controllers\TakaponController@index | web        |
|        | GET|HEAD | test/takapon/hoge | test.takapon.hoge | App\Http\Controllers\TakaponController@index | web        |
|        | GET|HEAD | test/takapon/huga | test.takapon.huga | App\Http\Controllers\TakaponController@index | web        |
+--------+----------+-------------------+-------------------+----------------------------------------------+------------+

また、こちらも複数繋げての指定も可能です。

例えば以下のような感じです。

Route::prefix('test/takapon')->name('test.takapon.')->group(function () {
    Route::get('hoge',[TakaponController::class, 'index'])->name('hoge');
    Route::get('huga',[TakaponController::class, 'index'])->name('huga');
});

こう指定すると...

+--------+----------+-------------------+-------------------+----------------------------------------------+------------+
| Domain | Method   | URI               | Name              | Action                                       | Middleware |
+--------+----------+-------------------+-------------------+----------------------------------------------+------------+
|        | GET|HEAD | test/takapon/hoge | test.takapon.hoge | App\Http\Controllers\TakaponController@index | web        |
|        | GET|HEAD | test/takapon/huga | test.takapon.huga | App\Http\Controllers\TakaponController@index | web        |
+--------+----------+-------------------+-------------------+----------------------------------------------+------------+

ちゃんと繋がってくれるんですね...!

他のまとめる方法

さて、他にもまとめる方法として、Resourcesメソッド...というものがあります。

ただし、この手法は少し癖があるため、それをある程度理解した上で使用する必要があります。

簡単に説明しておくと、RESTful APIという、RESTの原則(システム同志の連携の際に用いる考え方の一つ)に則った形でのAPI設計があり、その構築をする場合にとても便利な機能がこのResourcesメソッドです。

LaravelではEloquentのモデルをリソースとして考えた場合、そのリソースに対するアクションをこのResourcesメソッドで一括で作成できます。

例えば...

公式でも説明されていますが、Photoモデル...といったモデルがあったとします。

すると、そのモデルをリソースと考えると、作成や読み取り、更新削除...といった、基本的なアクションが必要になります。

そういったものはあらかじめまとめて作っちゃおうぜ!というのがResourcesのやれることなんですね。

実際に、一つルーティングを書いてあげれば最大7つ分ほどのルーティングを書いたことになりますし、それぞれのURIやnameも自動で作成されます。

ただ、既存のルーティングをまとめる...という用途とは少し違うので、今回はこの程度にしておきます。

使用する場合は、公式ページを参照してみてください。

余談

最後に、前述したRESTfulなルート指定ですが、以前は以下のようにも指定できました。

Route::controller('users', 'UserController');

上記をルーティングに指定した上で、"UserController"にて、以下のように指定すればいい感じにgetやpostで判別してくれてたんですね。

class UserController extends BaseController {
    public function getIndex()
    {
        //
    }

    public function postProfile()
    {
        //
    }

    public function anyLogin()
    {
        //
    }
}

しかしながら、上記の"Route::controller"は5.3の時点で廃止されているため、もう使えません。

調べていると、ちょこちょこ見かけたので、念の為記載しておきます。

上記の非推奨の項目として...

Route::controllerを使う暗黙のコントローラルート定義は非推奨になりました。ルートファイルで明確に定義してください。これはパッケージから削除されます。

とありますね。

まぁ、Controller以下が暗黙で定義されているとわかりづらい...等あるからでしょうね。

もしRoute::controllerは使えない...ことは気をつけていきましょう!(ただし、古い場合は使ってるものもあるかもしれないです。その場合はとりあえずバージョン上げるようにがんばりましょう...)

まとめ

さて、今回はルーティングをまとめる方法を見ていきました...!

いくつか方法があったりするのかな?

と思いましたが、現状はprefixとnameで括っていく形が最もベストな気がします。

公式の資料を眺めていると、アクセス回数の制限等もかけられることをしって、まだまだ使ったことない機能案外多いな...と改めて感じました...w

それでわ!

おすすめの記事