🐼

苗木「フォームからの送信値が全部string型になる……」

2021/09/05に公開

フォームからのデータは、いちいちキャストしないといけない?

苗木「モノクマに頼まれた、 学級裁判の議事録を投稿するシステムを作ろう」
苗木「必要なデータは、とりあえずこれかな」
・タイトル
・本文
・参加人数
・公開/非公開設定

苗木「HTML部分は、こんな風にして……」

create.blade.php
<form method="post" action="/create">
  @csrf
  タイトル:<input type="text" name="title">
  <br>
  本文:<textarea name="body"></textarea>
  <br>
  参加人数:<input type="text" name="number_of_people">
  <br>
  <input type="hidden" name="is_public" value="0">
  公開/非公開設定:<label><input type="checkbox" name="is_public" value="1">公開する</label>
</form>

苗木「POSTしたデータを、コントローラーで処理しよう! バリデーションは、フォームリクエストでやろうかな」

PostController.php
class PostController extends Controller
{
    public function store(StoreRequest $request)
    {
        // バリデーションチェックを通ったデータだけ取得
        $data = $request->validated();

        // DBに登録
        Post::create([
            'title'            => $data['title'],                  // タイトル
            'body'             => $data['body'],                   // 本文
            'number_of_people' => (int) $data['number_of_people'], // 参加人数
            'is_public'        => (boolean) data['is_public'],     // 公開/非公開設定
        ]);

        // 一覧ページにリダイレクト
        return redirect('/index')->with('message', '議事録を作成しました');
    }
}
StoreRequest.php
class StoreRequest extends FormRequest
{
    public function rules()
    {
        return [
            'title'            => ['required', 'string', 'max:255'],
            'body'             => ['required', 'string'],
            'number_of_people' => ['required', 'integer'],
            'is_public'        => ['required', 'boolean'],
        ];
    }
}

苗木「$request->validated();は、バリデーション後のデータを配列で持ってきてくれるから、便利だね」
苗木「それにしても、毎回思うんだけど……DBに登録するときのココ」

PostController.php
// DBに登録
Post::create([
    'title'            => $data['title'],                  // タイトル
    'body'             => $data['body'],                   // 本文
    'number_of_people' => (int) $data['number_of_people'], // 参加人数
    'is_public'        => (boolean) data['is_public'],     // 公開/非公開設定
]);

苗木「フォームから受け取った値は全部文字型だから、整数型は(int)、論理型は(boolean)みたいに、キャストしないといけないんだよね。これ、ちょっと面倒臭いなぁ」

葉隠「なーに言ってんだ、苗木っち。そんなの、こうすりゃいいんだべ!」

PostController.php
// DBに登録
Post::create([
    'title'            => $data['title'],            // タイトル
    'body'             => $data['body'],             // 本文
    'number_of_people' => $data['number_of_people'], // 参加人数
    'is_public'        => $data['is_public'],        // 公開/非公開設定
]);

葉隠「キャストなんかしなくても、Laravelっちがよしなにやってくれるべ!」
苗木「うーん……それはそうなんだけど……。やっぱり、型はちゃんと意識したいし、処理の途中で他のメソッドに値を渡すときは、やっぱりキャストしないとダメだよね?」

フォームリクエストから、キャスト済のデータを取得

霧切「苗木くんのクセに生意気なことを言うのね」
苗木「霧切さん!」
霧切「そんなときは、ココに一工夫加えればいいのよ」

PostController.php
// バリデーションチェックを通ったデータだけ取得
$data = $request->validated();

霧切「このvalidated()は、フォームリクエストの親クラス……つまり、FormRequestクラスのメソッドよ。苗木君、ここまで言えばわかるわね?」
苗木「いや、わかんないけど……」
霧切「StoreRequestクラスで、validatedメソッドをオーバーライドするのよ」

StoreRequest.php
class StoreRequest extends FormRequest
{
    public function rules()
    {
        return [
            'title'            => ['required', 'string', 'max:255'],
            'body'             => ['required', 'string'],
            'number_of_people' => ['required', 'integer'],
            'is_public'        => ['required', 'boolean'],
        ];
    }
    
    // ココでオーバーライド
    public function validated()
    {
        // バリデーションチェックを通ったデータだけ取得
	$validated = $this->validator->validated();
	// キャストしたデータをarra_mergeで上書き
        return array_merge($validated,[
            'number_of_people' => (int) $this->number_of_people,
	    'is_public'        => (boolean) $this->is_public,
        ]);
    }
}

苗木「そっか! そうすれば、$request->validated();で取得した段階で、既にキャストされてるんだね! 後は、葉隠クンがやったように、何も考えずにデータを渡せるんだ!」

PostController.php
class PostController extends Controller
{
    public function store(StoreRequest $request)
    {
        // バリデーションチェックを通ったデータだけ取得
        $data = $request->validated();

        // DBに登録
        Post::create([
            'title'            => $data['title'],            // タイトル
            'body'             => $data['body'],             // 本文
            'number_of_people' => $data['number_of_people'], // 参加人数
            'is_public'        => $data['is_public'],             // 公開/非公開設定
        ]);

        // 一覧ページにリダイレクト
        return redirect('/index')->with('message', '議事録を作成しました');
    }
}

霧切「余談だけど、フォームリクエストで論理型にキャストするときのココ」

'is_public' => (boolean) $this->is_public

霧切「Laravel6系以降なら、論理型を取得するための専用メソッドも用意されているわ」

'is_public' => $this->boolean('is_public')

// 普通のリクエストでも
'is_public' => $request->boolean('is_public')

苗木「ありがとう、霧切さん!フォームリクエストって、奥が深いんだね!」
霧切「ええ、バリデーションだけじゃなくて、色々なことができるわ。興味があったら、調べてみてちょうだい」

Discussion