new takyam();

Qiitaぽい話はQiitaに書いていくことにする気がする http://qiita.com/takyam

Laravel 4 で今日触った事(MongoDB, ルーティングネーム, Redirect withInput)

今日も引き続きLaravel4ネタ。
昨日ご紹介した本はサクッと読み終わり、大変勉強になりました。ありがとうございました。

さて、今日は少しだけ触ってみたのでメモがてら使い勝手を書きます。

  • MongoDB ( MongoLid )
  • ルーティング名
  • Redirect withInput

MongoDB

Laravel用のMongoDB周りのORM(ODM?)はいくつかあるみたいですが、今回は以下のライブラリを使用しました。

Zizaco/mongolid-laravel
Easy, powerful and ultrafast MongoDB ODM for Laravel.
https://github.com/Zizaco/mongolid-laravel/wiki

いやもう「ultrafast」とか「crazy fast」とかに弱くて・・・。

「Easy」って言ってるだけあって超簡単でした。インストール方法はドキュメント見てもらうとして、Modelとして最低限、定義する必要があるのは以下だけ。とりあえずね。

<?php
// app/models/Hoge.php
class Hoge extends MongoLid {
    protected $collection = 'hoges'; //コレクション名を定義
    //バリデーションルールを設定
    public static $rules = array(
        'fuga' => 'required', //fugaは入力必須
    );
}

Mongoだからスキーマ定義しなくていいから超短いね!だからなんだって話だけど!
で、使う時はこんな感じ

保存時のControllerの中身的なやつ
<?php
//HogeモデルのインスタンスをIoCコンテナ経由で作成。new Hogeとかダサいからダメだよ!
$hoge = App::make('Hoge');

//fugaプロパティにPOST値をセット
$hoge->fuga = Input::get('fuga');

//バリデーションを実施。 $rulesスタティックプロパティに fuga の required が設定されてる。
if ($hoge->isValid()) {
    //保存を実施する
    $hoge->save();
    //成功時の処理
} else {
    //失敗時の処理
}
取得する時はこんな感じ
<?php
class HogeController extends BaseController{
    //Hogeを直接使わないでちゃんとIoCコンテナ経由で!
    public function __construct(Hoge $hoge){
        $this->hoge = $hoge;
    }
    public function index(){
        //Viewに
        $this->layout->content = View::make('hoge/index')
            ->with('hoges', $this->hoge->all());
    }
}

結構楽ちんっすね。Validation周りの処理をよしなにやってくれるisValid()メソッドが最初から作られてるので自前で作らなくてもOKっす。(込み入った事しようとしたらいじる必要あるでしょうが)

全然使いきれてないのでリレーションとか集計系とかどうなってんのかはまだ見れてませんが、保存と表示くらいだったら簡単にできそうですね。

ルーティング名

Laravelのルーティングはroutes.phpとかにルーティングを定義していくわけですが、ルーティングひとつひとつに名前を設定できるみたいです。

app/routes.php
<?php
Route::get('hoge/create', ['as' => 'hoge.create', 'uses' => 'HogeController@create']);

'as'にルーティング名(エイリアス)を設定して、'uses'にコントローラを指定します。これで何ができるかっつーと、リダイレクトとかする時にエイリアスで指定できて何か気持ちいい。

<?php
return Redirect::to('/hoge/create');

//↑これを↓にできる

return Redirect::route('hoge.create');

こんな感じ。気持ち良いですね。

Redirect with input

RedirectクラスにwithInput()メソッドがあるってだけの話なのですが、好き嫌いはあるでしょうが、お手軽に諸々できるので良いかと。

先ほどの例と組み合わせると以下のような感じ。

<?php
class HogeController extends BaseController{

    protected $hoge;

    public function __construct(Hoge $hoge){
        $this->hoge = $hoge;
    }

    //作成画面の表示アクション
    public function create(){
        $this->layout->content = View::make('hoge/create')
            ->with('hoge', Session::getOldInput('hoge', null)); //旧入力があれば取得
            //エラーは自動で$errorsでViewにセットされる
    }

    //作成画面の保存処理アクション
    public function save(){
        //HogeモデルのインスタンスをIoCコンテナ経由で作成。new Hogeとかダサいからダメだよ!
        $hoge = App::make('Hoge');

        //fugaプロパティにPOST値をセット
        $hoge->fuga = Input::get('fuga');

        //バリデーションを実施。 $rulesスタティックプロパティに fuga の required が設定されてる。
        if ($hoge->isValid()) {
            //保存を実施する
            $hoge->save();
            //成功時はインデックスページにリダイレクトする
            return Redirect::route('hoge.index');
        } else {
            //失敗時は作成ページにリダイレクトしてエラーを表示させる
            return Redirect::route('hoge.create')
                ->withInput() //入力値を添えて
                ->withErrors($hoge->errors); //エラーを添えて
        }
    }   
}

ポイントはまず、バリデーションエラー時に、作成画面にリダイレクトする処理です。

<?php
//失敗時は作成ページにリダイレクトしてエラーを表示させる
return Redirect::route('hoge.create')
    ->withInput() //入力値を添えて
    ->withErrors($hoge->errors); //エラーを添えて

hoge.createに入力値(withInput())とエラー(withErrors())を添えてリダイレクトしますよー。」的なニュアンスです。

で、この「添えて」っていうのが「Sessionに格納して」(たぶんflash)リダイレクトするっていう意味なので、作成画面の表示側ではSessionから添えられた内容を取得して表示します。

<?php
View::make('hoge/create')
    ->with('hoge', Session::getOldInput('hoge', null)); //旧入力があれば取得
    //エラーは自動で$errorsでViewにセットされる

旧入力はSession::get('_old_input')でも取得できるんですが、イケてないんでSession::getOldInput('hoge', null)のように取得しましょう。
エラーに関してはそのままSession::get('errors', null)で取得できるんでそのように。
エラーに関してはそのままViewにセットされるのでViewから$errorsを使いましょう。

値の復元をセッションを使って行い、画面表示をGETリダイレクトにする方式に、名前があるのかは知りませんが、このパターンを使う事で、「戻る」ボタン押してもブラウザに怒られないメリットを抱えつつ「セッションを使う」ので、フォームの種類によってはあまり向いてない事(巨大な文字列データを送信するとか、セッションストレージがmemcachedなのだけどメモリがほぼ無いとかw)もあると思うので、その辺は適宜判断しつつ。


まとめ

というわけでちょろっとだけ使ってみて感じたのは、プラクティスが非常にシンプルに、良い感じで詰まってるフレームワークだなという印象です。

Redirect::withInput()Session::getOldInput()はWAFレベルで提供するにはやりすぎな気もしつつ、プラクティスのひとつを簡単に使えるようになっているので、初心者が何も考えずに使うもよし、熟練者が納得した上でプラクティスに乗っかるのも楽でよし、というわけで、良いなぁと。

とりあえず「READ」と「CREATE」の部分だけ触ってみたので、次はここのテスト書いてみつつ(テストアフターだいちゅき(^ρ^))、「EDIT」と「DELETE」を試してみたりとかやってみる予定です。

「ぐへへ、、、IoCコンテナ使ってやるぜ、、、」って思いながら書けるので、モチベーションは無駄に高まりますね。別に大した事やってる訳じゃないんですが、何か「ナウい」コード書いてる感がパネェっす。


追記(2013/07/16 16:40)
エラーのViewへのセットの部分についてご指摘いただいたので修正