Laravel3、ルーティングの書き方

タグ: Laravel3  

ルーティングの書き方に決まりはありません。唯一、先に定義したほうが優先的に取り扱われることが、動作上の決め事です。

Laravelはルーティングの指定が柔軟であるが故に、全てを使用しようとすると、読みやすさ、わかりやすさが損なわれてしまいます。そのためある程度は自分でコーディング規則を決めたほうが使いやすいでしょう。

こうした規則は比較的大きなシステム、アプリを作成するときほど厳密に適用すべきです。もし、ちょっとした簡単な使い捨てのシステムを作成するだけならば、厳密に行うより、素早く作成できる方法を取るのは決して間違いではありません。(得てして、そうしたアプリが機能追加でどんどん大きくなるのはありがちな話しですが… :D )

自分流、もしくは組織立った開発を行う場合にコーディング規則を作成するためのヒントです。

絶対規則

Laravelのシステム上の決め事は、先に定義したルートが、後のものより優先されるという事です。つまり、routes.phpで登録した順番に、チェックされます。

これは、定義するルートに(:all)(:any)(:all?)(:any?)を含むルートを使用する場合、十分に注意し、定義順を考える必要がるという事です。これはLaravelに限った問題ではありませんね。他のフレームワークでもおなじみです。

基本的に適用範囲が広いルートは後ろで、限定的なルートは先に定義しましょう。これはLaravelの決め事ですから、変更はできません。

全てを一目瞭然に

可能な限り、application/routes.phpを読んだだけで、ルートの動きが把握できるように記述しましょう。

例えば、コントローラーのコンストラクタでもフィルターを定義できますが、これを採用してしまうと、コントローラーをいちいち確認しないと、そのルートに適用されるフィルターがわからなくなります。更にLaravel4では、コンストラクタ内でもフィルターが定義できるようになり、これを使ってはお手上げです。

Laravelの機能の中には、お手軽に作成するためのものと、大きなアプリ向けのカチカチのシステム向けの機能があることをお忘れなく。

可読性のため、フィルターの指定は全てroutes.phpの中で記述することをおすすめします。

無名関数ルートの使用制限

きちんとコーディングルールを決めるレベルのアプリであれば、全てのルートを無名関数でroutes.phpの中に記述するのは、見づらくなり、可読性を低下させます。

かと言って、全てをコントローラーに入れるべきだとは主張しません。なぜなら、コントローラーの増加も複雑性を増すからです。確かに、コントローラーに押し込みづらいルートもあります。

もし、大人数で開発する場合は、当然ながら全部をコントローラーに入れる開発になるでしょう。逆に個人で複雑なアプリを作成する場合でしたら、判断はその人の好みによります。

ルート指定方法の統一

ルートの定義はルート名を定義するか、もしくはコントローラー/アクションによる指定のどちらかに統一しましょう。

無名関数とコントローラー両方のルーティング両方を使用する場合、統一しようと思えば、必然的に名前付きルートを採用することになります。名前はどちらのルートにもつけることができます。

Route::any('adminlogin', array('as' => 'admin-login', function() {
   // ログイン処理 
}));

Route::any('user/add', array('as' => 'user-add', 'uses' => 'user@add'));

コントローラーだけを使用する方針の場合は、コントローラー/アクションに統一しましょう。

Route::any('post/show', 'post@show');
Route::any('post/delete', array('before' => 'auth', 'uses' => 'post@show'));

グローバルbeforeフィルター

routes.php中では、全ルートの直前に制御が移ってきます。ですから、自前のセットアップに活用できます。

Route::filter('before', function() {
    // セットアップに必要なコード
});

ところがこれも書きすぎてしまうと、このグローバルbeforeフィルターが肥大化し、可読性が落ちてしまいます。

その場合、同じroutes.phpの中でもLaravelのシステムの準備が整った時点で呼び出されるイベントのリスナーとして登録する方法があります。

Event::listen('laravel.started: sample', function() {
    // セットアップに必要なコード
    // イベントはいくつも登録できるため、更に分割し、別ファイルに記述する方法もある。
});

もしくは、初期処理用のクラスを作成し、そこでまとめて処理しましょう。例えば、application/libralies/app.phpを作成します。

class App {
    public static function init() {
        // ここにアプリのセットアップ
        // 機能により関数を分けたほうが、テストはしやすい
    }
}

そしてグローバルbeforeフィルターか、Laravel開始イベントリスナーの中でApp::init()を呼び出します。

同じフィルターの適用

全く同じフィルターを適用するのでしたらパターンフィルターやルートグループの使用を考えてください。

パターンフィルターは、あるパターンに一致するルート全部に、同一のフィルターを指定する方法です。例えば、管理者側で使用するルートをadmin/というURIの下にまとめることはよくあることでしょう。当然このパターンに当てはまるルートは全部認証されているユーザーしか、利用できません。ですから、authフィルターを適用する必要があります。

Route::filter('pattern: admin/*', 'auth');

いちいち、全ルートに指定するよりも記述がすっきりし、手間も省けます。

URIに共通性がないが、同じフィルターを使用するものは、ルートグループとしてまとめて指定ができます。

Route::group(array('before' => 'auth'), function()
{
    Route::get('systeminfo', 'system@showinfo');     
    Route::get('dashboard', function()
    {
        return view('dashboard');
    });
});

安全性を高めるため、全てのPOSTメソッドに対し、CSRFフィルターを指定したい場合もあるでしょう。残念ながら、Laravelにはその機能はありません。

ルートグループを使用し指定するか、POSTルートには個別に指定する事になります。私は個別に指定する方法が好きです。もしくは全部コントローラーを使用する開発スタイルを採用されるかたであれば、このPOSTルートに対するCSRFフィルターの指定は、例外として各コントローラーのコンストラクタに書くか、BASEコントローラーで指定しましょう。