LoginSignup
150
152

More than 3 years have passed since last update.

LaravelのFormRequestクラス機能まとめ

Last updated at Posted at 2019-06-20

概要

LaravelのFormRequestクラスの使い方と機能のまとめです.

環境

Laravel 5.5

準備

まずは次のコマンドでFormRequestクラスを生成します.

artisan make:request TestRequest

ファイルは,app/Http/Requests/TestRequest.php に作成されます.作成されたファイルで

app/Http/Requests/TestRequest.php
public function authorize()
{
    return true; // 元はfalse
}

に変更することで使用できます.

使い方は,使用するコントローラなどで

ExampleController.php
use App/Http/Requests/TestRequest;

class ExampleController extends Controller
{
    public function testMethod(TestRequest $request) {
        /* 処理 */
    }
}

とすることで使用できます.

機能

バリデーション

ruleメソッドに連想配列・文字列で記述します.

app/Http/Requests/TestRequest.php
public function rules()
{
    return [
        'price' => ['required' , 'integer' , 'min:1'],
        'discount' => 'required|integer',
    ];
}

このように,バリデーションルールを配列または文字列で指定できますが,配列で指定することをおすすめします.理由は後々の拡張性や可読性,一部ルールでは配列での指定が必須なので後々のことを考えると配列を使用したほうが良いからです.

使えるバリデーションルールはドキュメントにあります.

自分で作成したバリデーションを使う

Laravelでは用意してあるバリデーションルールを組み合わせれば,大抵のバリデーションができますが,それでも特殊なバリデーションを行いたいことが多々あります.その場合は

app/Http/Requests/TestRequest.php
public function withValidator($validator) {
    /* ここにバリデーションを書く */
}

を追加します.ドキュメントによれば
「このメソッドは完全に構築されたバリデータを受け取るため、バリデーションルールが実際に評価される前に、バリデータのどんなメソッドも呼び出すことができます。」
とあり,このメソッドではruleで指定したバリデーションルールが適用される前のバリデータにアクセスできます.

使い方は,例えば「割引額(discount)が支払金額(price)よりも小さい」ことをバリデートする場合は,

app/Http/Requests/TestRequest.php
public function withValidator($validator) {
    $validator->after(function ($validator) {
        if($this->filled(['discount','price'])) {
            if($this->input('discount') >= $this->input('price')) {
                $validator->errors()->add('割引額', '合計金額より小さい額を指定してください.');
            }
        }
    });
}

とします.ルールメソッドとは異なり,直接メッセージや項目名を指定します.もし,rulesで指定したチェックを通過した場合のみ追加チェックを行いたい場合は

public function withValidator($validator) {
    if ($validator->fails()) return;
}

とすることで分岐することができます.

エラーメッセージの変更

エラー時の各項目のメッセージを

app/Http/Requests/TestRequest.php
public function messages()
{
    return [
        'discount.integer' => '整数で指定してください.',
        'price.integer' => '整数で指定してくださいませ.',
    ];
}

で変更できます.キーは「項目名 . ルール」となっています.

エラーメッセージの項目名の変更

ルールメソッドで指定したバリデーションで,エラーが返ってきたときにのメッセージの項目名を

app/Http/Requests/TestRequest.php
public function attributes()
{
    return [
        'discount' => '割引額',
        'price' => '合計金額',
    ];
}

で変更できます.

バリデーションデータの追加

apiなどではjson形式でデータを送信することがありますが,このようなときにデータを展開してバリデーションにかけるには,

app/Http/Requests/TestRequest.php
//オーバーライド
protected function validationData()
{
    $data = json_decode($this->input('json'), true);
    return $this->all() + ['data' => $data];
}

とします.バリデーションは

app/Http/Requests/TestRequest.php
public function rules()
{
    return [
        'data.price' => ['required' , 'integer' , 'min:1'],
        'data.discount' => 'required|integer',
    ];
}

でかけれます.ネストにしたくない場合は,'data' => $data$dataにしたり

protected function validationData()
{
    $inputs = $this->all();
    $inputs['json'] = json_decode($this->input('json'), true);
    return $inputs;
}

として,入力を上書きします.

これはバリデーションがかけられるデータがvalidationDataメソッドの返り値に対してかけられるため,元のデータにマージしてデータを追加することでバリデーションがかけられるデータを追加しています.したがってjsonにかかわらず別のデータを追加することもできます.例えば,ルートパラメータを追加する場合は

protected function validationData()
{
    return $this->all() + $this->route()->parameters();
}

とします.

入力値の整形

例えば,日付の入力フォームが年・月・日で別れている場合など,それらを結合したデータを追加することができます.

protected function passedValidation()
{
    $date = Date::createMidnightDate($this->input('year'), $this->input('month'), $this->input('day'));

    $this->merge([
        'date' => $date,
    ]);
}

また,年月日が一つのフォームになっていたとしても,そのままでは文字列型なので,

protected function passedValidation()
{
    $this->merge([
        'date' => Date::parse($this->input('date')),
    ]);
}

とすることで,コントローラ側で入力値をCarbon型で受け取ることができます.

$request->input('date');  // Carbon

メソッドの追加

FormRequestクラスに追加したメソッドは,呼び出すことができます.例えばCSVファイルを受け取る場合,

app/Http/Requests/TestRequest.php
public function getCsvData()
{
    $csvFile = $this->file('csv');
    $csvData = array();
    /* 受け取ったCSVファイルをからデータを取り出す */
    return $csvData;
}

のようにメソッドを追加すれば,コントローラ側で

ExampleController.php
class ExampleController extends Controller
{
    public function testMethod(TestRequest $request) {
        $csvData = $request->getCsvData();
    }
}

とすることで,CSVファイルのデータを受け取れます.他にも,json形式でデータを受け取る場合では

app/Http/Requests/TestRequest.php
public function decodedData()
{
    $data = $this->all();
    $data['json'] = json_decode($data['json'], true);

    return $data;
}

としてしまえば,コントローラ側でjson_decodeをかける必要がなくなります.前段のように

protected function passedValidation()
{
    $this->merge([
        'json' => json_decode($this->input('json'), true),
    ]);
}

としても良いと思います.

入力値の取得

FormRequestから入力値は以下のように取り出すことができます.

// すべて取り出す
$request->all();
$request->input();

// 一つだけ取り出す
$request->input('data', 'デフォルト値');
$request->data;

// 複数取り出す
$request->only(['data1', 'data2']);

// 指定したもの以外を取り出す
$request->except(['data3']);

これを使うことで,モデルの更新などを

$user = User::findOrNew($request->id);
$user->fill($request->except('id'));
$user->save();

このように書くことができます.

まとめ

FormRequestクラスを用いることで,バリデーションとコントローラを分離することができ,可読性や機能管理が容易になります.また,送信データに対する一次加工(json_decodeなど)もこちらに含めてしまえば,コントローラ側でデータを加工する手間が省けます.

参考

150
152
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
150
152