laravel5.1 フォーム入力→バリデーション→保存の流れのメモ

__laravel5.1 @php5.6__

うちではこうしてるなどありましたら教えていただけると嬉しいです！

作っているのは小規模なもので、保存処理は
EloquantModelから行っています

## 処理の流れ

記事情報の入力→保存みたいなイメージをしていただければと
なので__ArticleController__と
EloquantModelを継承した__Article__モデルが登場します

__①リクエストパラメータを処理__

```
Requestの値を加工したい場合はmiddleware。

or

コントローラから定義したサービスにリクエストを渡してやらせる。
```

しょっぱなから悩んでいます笑
方針的には、後者にしたんですがせっかくLaravelはmiddlewareを提供しているのに
コントローラにやってくるRequestをさらにいじるのはどうなんだろうかと。。

Requestの値をいじるというのは、ユーザidをセットしたり
配列で送られてくるデータをカンマ区切りにすることを今回は行いました。

__②コントローラでの処理__

postのみ受け付けるというactionをコントローラに定義
(routes.phpにて)

ここでは、単純にpostアクションとします。

```php:ArticleController.php

    /**
     * @param Request $request
     * @return $this|\Illuminate\Http\RedirectResponse
     */
    public function post(Request $request)
    {
        $article = new Article($request->all());
        $validator = $article->validate();
        
        //バリデーション失敗
        if ($validator->fails()) {
            return redirect()
                    ->route('Failure')
                    ->withErrors($validator) //バリデーション結果をビューにセット。$errorsで参照できるようになる
                    ->withInput(); //入力値をビューにセット
        }

        //バリデーションが通ったら保存
        $article->save();
        Session::flash('flash_message', '記事の作成に成功しました');
        return redirect()->route('Success');
    }

```

### コントローラの詳細

一行目、Articleモデルに$request->all()で入力値を配列に展開したものを渡す。

こうすることで継承したEroquantモデルのコンストラクタが
渡されたパラメータに対してfill()メソッドを実行する。

そうすると、サブクラスのモデル定義に合わせてattributesに値をマッピングしてくれる。

ここでいうサブクラスのモデル定義とは
__$fillable__や__$guarded__のこと

下記のモデル参照

```php:Article.php

class Articles extends Model
{
    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'articles';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'column1', 'column2', .....
    ];

```

$fillableはfillメソッドが走ったときに定義した値しか
モデルのattributesに入らないようにする。

なので、__モデルに不要な値が入り込まないことを保証する。__

例えば$request->all()に通常csrfトークン(['_token' => 'fashfe'])が
入っていると思うがfillメソッドが弾いてくれる。

また悪意あるユーザがidをhiddenパラメータで送ってきたときに
該当idでデータがインサートされることを防げる。

なので、入力されるべき値はfillableで必ず定義すること。

### コントローラの詳細続き

コントローラの一行目解説から長くなりました。。

自分は、Articleモデルでバリデーションを行うようにしたので
その呼び出し先を見てみます。

```php:Article.php
class Articles extends Model
{
 
    private $rules = [
        'column1' => 'required|exists:category,id',
        'column2' => 'required|max:255',
        .
        .
        .
    ];
    
    /**
     * @return mixed
     */
    public function validate() {
        return Validator::make($this->attributes, $this->rules);
    }

```

Articleモデルにて、行いたいバリデーションを定義しておいて
Validator::makeの第2引数に渡す。
第1引数には、モデルのattributesを渡す。

この値は、先程のコンストラクタでRequastデータを基に
保存したいものだけが入っています。

バリデータオブジェクトを返しているのは、コントローラからビューに
バリデーション結果を渡したいからです。

__ただ、現状はモデルが中途半端にバリデーションの責務を持っている感じがするので
コントローラはただモデルに問い合わせればバリデーションができるようにしたほうがいいのかな。。__

モデルにtraitでバリデートの振る舞いをつけるとか。。

### コントローラの詳細続き

あとは簡単ですね。
バリデーション結果に応じて保存を行ったり
リダイレクト処理を行うだけです。一応もう一度コントローラのせておきます

ちなみに

```php
$article->save()
```
でモデルにセットされたattributesを基にクエリを生成しインサート処理を実行しています

```php:ArticleController.php

    /**
     * @param Request $request
     * @return $this|\Illuminate\Http\RedirectResponse
     */
    public function post(Request $request)
    {
        $article = new Article($request->all());
        $validator = $article->validate();
        
        //バリデーション失敗
        if ($validator->fails()) {
            return redirect()
                    ->route('Failure')
                    ->withErrors($validator) //バリデーション結果をビューにセット。$errorsで参照できるようになる
                    ->withInput(); //入力値をビューにセット
        }

        //バリデーションが通ったら保存
        $article->save();
        Session::flash('flash_message', '記事の作成に成功しました');
        return redirect()->route('Success');
    }

```

## まとめ

試行錯誤しながら↑にいたりましたが、
Laravelは自由度が高い分、自分がやってることが正しい手順なのかがわからなくなった。

どうやって道を整備するかといったら、やはりフレームワークの機能が
うまく使えているかに戻るのがいいのではないかと。

そうすれば、必然とコードの量も減るし後から改修もしやすい。
何かふんわりしたままコードの量が増えるのが危険。
大体のことはフレームワークに用意されているのだから。

特にバリデーションの定義については相当込み入ったことをやらない限り
カスタムバリデーションを定義する必要はないのではと思う。

Laravel開発楽しい笑