Help us understand the problem. What is going on with this article?

Laravelのエラー処理を強引に簡略化する

More than 5 years have passed since last update.

Laravel Advent Calender 10日目です。
区切りの良い節目の日に大遅刻をやらかしました。申し訳ありません。

自己紹介

職業プログラマ3年目、Laravel歴半年の若造です。
大学では酒作りの研究をしていましたが物理的に道を踏み外し大負傷、死なない仕事を求めこの職へ。
業務では主にPHP, Perl, jQueryを扱っています。

Laravelのエラー処理って迷いません?

例えばこんなことをServiceやModelで行う。

バリデーションエラー
$val = Validator::make(Input::all(), $rule);
if ($val->filed()){
  return Redirect::to('url')->withErrors($val);
}

こうすれば勝手にViewsで$errors変数を展開してくれる。こりゃ便利。
だがちょっと待て。このままでは私のWeb的MVCに対する信仰心が示せない。
リダイレクトはコントローラの役割だ。Serviceはbooleanでも返してろ。

そして深い階層で起こるエラーに悶える

Serviceで起こったエラーならまだ良かった。
Modelで起こったエラーをWeb的MVCでViewまで持ってくるにはServiceを経由してコントローラを経る必要がある。
エラーをモデルクラスのメンバ変数に格納しそれをServiceから呼びcontrollerへ送りwithErrors・・・
更にValidatorインスタンスを呼び出していない状態での共通エラーの扱いが面倒。
new Illuminate/Support/MessageBagを明示的に呼び出すのも気持ち悪い。
そこまでするなら配列で直接コントローラまで持っていったほうが扱いも楽。

正直めんどい。

morisukeは激怒した。暴虐非道の王Laravelを正さねばならぬ。
そうして覚えたてのIoCコンテナを使うことを思いついたのが先月の中頃でした。

Singletonを利用する

LaravelではIoCコンテナの機能としてSingletonが提供されています。
App::singletonをroute,phpなどに記述することでどこで何度newしても一意のインスタンスを呼び出せるようになります。
それをこう使います。

App::singleton('Error', function() {
    return new Illuminate/Support/MessageBag;
});

単なるMessageBagインスタンスのシングルトンです。
これをこう使います。

Serviceのエラー箇所
public function validateInput($input, $rule){ 
  $val = Validator::make($input, $rule);
  if ($val->filed()){
    App::make('Error')->merge($val->messages()->getMessages());
  }
}
コントローラのリダイレクト箇所
$this->service->validateInput(Input::all(), $rule);
$errors = App::make('Error');
if ($errors->has()){
  return Redirect::to('url')->withErrors($errors);
}

シングルトンの魅力は何と言っても model, service, controller,どこで呼び出しても 同じインスタンスを返すことです。
どれだけ深い階層でエラーが起ころうがコントローラで見るべきものはApp::make('Error')ただひとつ。
App::make('Error')->has()を行えばエラーが発生したかどうかの判別も行えます。
serviceはfalseすら返す必要がなかった!お前はもう何もしなくていいんだ、ゆっくり休め!

かなり強引な方法ですが、実際に扱ってみるとかなり便利であることが分かって頂けると思います。
また共通エラーとフォームエラーの分離のためにmergeではなくaddを利用し、

App::make('Error')
  ->add('common', $common_error)
  ->add('form', $validator->messages()->getMessages());

などとすることでViewでの扱いを楽にすることも出来ます。
是非お試しあれ。

こんなことしなくてもLaravelのエラー処理にはもっと楽な方法があるよ!
という意見や感想はコメントでどんどん教えて下さい。
私自身まだまだLaravelの勉強中ですので、皆さんの知識を分け与えて下さると幸いです。

以上、Laravel Advent Calender 10日目。
「Laravelのエラー処理を強引に簡略化する」でした。
明日の担当はHiroKwsさんです。宜しくお願いします!

morisuke
Vue.js / Laravelが得意。ご連絡はメールかTwitterでどうぞ。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした