速習Larave3(その5)、コントローラー
タグ: Laravel3
コントローラーを使いはじめましょう。
- ソース:github
さて、前回作成したroutes.phpをご覧ください。
随分コードが増えてきました。Laravelの特徴…というか、他のフレームワークでも採用されていますが、コントローラーを使用せず、無名関数を使用してルーティングに直接コードを記述できるようになっています。
これは、全部で数ページのサイトとか、ちょっとしたツールを作成するとか、機能を実験してみるとかには、とても便利に使用できます。
ですが、routes.phpはその名の通り、ルーティングの定義がメインです。まだ、3ページ分のルートしか定義していないのに、全部のルートを見通すのが難しくなっています。
つまり、ルートを調べるという事に関しては、可読性が落ちています。Laravelが折角、読みやすいPHPの世界を作ってくれているのに、その一部の機能を利用して壊しているのです。これはもったいない。対処しましょう。
ということで、今回からコントローラーを使いはじめましょう。どこに入れたらいいか迷うような小さなルーティングの内容ならともかく、可能な限りroutes.phpには、ルートの定義だけ記述して、すっきりさせます。それでなくてもフィルターとか、その他の定義が集まりごちゃごちゃしますからね。
Tips!! その内なるボヤキが聞こえたのか、Laravel4ではフィルターの定義は別ファイルになりました。Laravel3でもファイルを分け、routes.phpでrequireしてすっきりさせる方法は取れます。
まず、コントローラーを作成し、そこに記事に関する操作を移動します。application/controllers/post.phpを作成してください。
<?php
class Post_Controller extends Base_Controller
{
    // レストフル動作フラグ
    public $restful = true;
    /**
     * 一覧表示
     */
    public function get_index()
    {
        $posts = Post::order_by('created_at', 'desc')->get();
        return view('post.index')
                ->with('posts', $posts);
    }
    /**
     * 記事表示
     */
    public function get_show($id)
    {
        $post = Post::find($id);
        if ( $post === null )
        {
            return Redirect::error('404');
        }
        return View::make('post.show')
                ->with('title', $post->title)
                ->with('body', $post->body);
    }
    /**
     * 記事追加フォーム表示
     */
    public function get_add()
    {
        return view('post.add');
    }
    /**
     * 記事追加フォーム処理
     */
    public function post_add()
    {
        // バリディーションルール
        $rules = array(
            'title' => 'required|max:50',
            'body' => 'required|max:8000',
        );
        $input = Input::only(array( 'title', 'body' ));
        $val = Validator::make($input, $rules);
        if ( $val->passes() )
        {
            // バリデーション通過
            // 新ポストの追加
            $post = new Post($input);
            $post->save();
            // 続けて追加できるように、
            // フォームは空のままリダイレクト
            return Redirect::to_route('post-add')
                    ->with('message', '記事を追加しました。');
        }
        else
        {
            // バリデーション失敗
            // バリディーションで生成されたエラーと
            // フォームに入力された内容を
            // セッションのフラッシュデーターを通じ
            // フォームに送る
            return Redirect::to_route('post-add')
                    ->with_errors($val->errors)
                    ->with_input();
        }
    }
}
当然のことながら、前回まで積み上げてきたコードと同じですね。違っているのは関数名が付くことくらいでしょう。
関数名の命名規則は他のフレームワークとよく似ています。通常はプレフィックスにaction_を付けます。それ以降の名前がアクション名となります。アクション名とはルーティングで指定される名前のことです。
今回はRESTルーティング、RESTフルなルーティングを使用します。これはプレフィックスがリクエストのHTTP変数の名前になる命名規則を使用するという事です。例えばGETメソッドでのアクセスはget_が頭に付き、POSTメソッドならpost_です。これを使用するにはコントローラーの$restfulプロパティをtrueにセットします。
続いて、routes.phpを改良しましょう。
<?php
/*
 * ルーティング定義
 */
// トップページ:一覧表示
Route::get('/', array( 'as' => 'post-index', 'uses' => 'post@index' ));
// 記事表示
Route::get('/post/(:num)', array( 'as' => 'post-show', 'uses' => 'post@show' ));
// 記事追加
//  フォーム表示
Route::get('/post/add', array( 'as' => 'post-add', 'uses' => 'post@add' ));
//  フォーム処理
Route::post('/post/add', array( 'as' => 'post-add', 'before' => 'csrf', 'uses' => 'post@add' ));
/*
 * エラー処理
 */
Event::listen('404', function() {
        return Response::error('404');
    });
Event::listen('500', function() {
        return Response::error('500');
    });
/*
 * フィルター定義
 */
Route::filter('before', function() {
        // Do stuff before every request to your application...
    });
Route::filter('after', function($response) {
        // Do stuff after every request to your application...
    });
Route::filter('csrf', function() {
        if ( Request::forged() )
            return Response::error('500');
    });
Route::filter('auth', function() {
        if ( Auth::guest() )
            return Redirect::to('login');
    });
/*
 * ビュー・コンポーサー定義
 */
View::composer('template',
    function($view) {
        $view->warning = isset($view->warning) ? $view->warning : Session::get('warning', false);
        $view->message = isset($view->message) ? $view->message : Session::get('message', false);
    });
どうでしょうか。コードが少なくなり、すっきりしました。一番重要なのは先頭のルートの定義が読みやすくなったという事です。これで他の人が呼んでも分かりやすくなりました。他の人の中には、半年後の自分も含まれています。
ルーティングの定義では'as'を使いルート名、'uses'を使いコントローラーとアクションを定義しています。
もし全体をコントローラー/アクションだけで統一するのであれば、ルート名は無理に必要ありません。コントローラー/アクションの指定でリンクを生成できるからです。名前とコントローラー/アクションのどちらでもリンクやURL、URIを生成できるのですが、便利でも両方を混ぜて生成するとごちゃごちゃになりますので、どちらか一方を使用しましょう。
今回は無名関数でのルーティングを完全に使用しないとは決めず、必要に応じて使用し、無名関数のルーティングとコントローラーを両立させようと思います。ですから、ルートには全部名前を付け、その名前でリンクを生成する方針をとっていきます。