はじめに

/events?areas=1,2,3 のような URL で検索などの処理を行う際に、良い感じにバリデーションする方法を調べた。

※なるべく自前で各値が DB の値と一致するかを検証したくないよね、というお話。

TL;DR

  • prepareForValidation 内でデータを変更すると幸せになれる
  • getValidatorInstance でもいけるかも(試してない)

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. 前置き: バリデーションについて
    2. 課題: URL について
    3. 解決方法: prepareForValidation を使う
    4. その他のやり方
  5. まとめ
  6. その他・メモ
  7. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.1
BuildVersion: 19B88

$ php -v
PHP 7.3.9 (cli) (built: Sep 10 2019 17:45:01) ( NTS )

$ composer -V
Composer version 1.9.0 2019-08-02 20:55:32

$ composer info laravel/framework
name : laravel/framework
versions : * v5.7.28

詳細

prepareForValidation を使って解決する。

前置き: バリデーションについて

Laravel では FormRequest のルールで配列の検証も簡単に実現できる。

配列の中身が DB に存在するかの検証も合わせて行うことができる。

1
2
3
4
5
6
7
8
9
10
class EventSearchRequest extends FormRequest
{
public function rules()
{
return [
'areas' => 'array',
'areas.*' => 'integer|exists:areas,id',
];
}
}

課題: URL について

ただし、そのまま恩恵に与ろうと思うと、下記のような URL を使う必要がある。
※POST などのフォームというよりは、検索など GET 系に主眼を置いている。

1
/events?areas[]=1&areas[]=2&areas[]=3

もっとシンプルに /events?areas=1,2,3 のような URL としつつ、値が DB に存在するかどうかも検証したい。

解決方法: prepareForValidation を使う

そのような場合は prepareForValidation を使ってこうすると良い。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class EventSearchRequest extends FormRequest
{
public function rules()
{
return [
'areas' => 'array',
'areas.*' => 'integer|exists:areas,id',
];
}

protected function prepareForValidation()
{
if ($this->areas) {
$this->merge([
'areas' => explode(',', $this->areas)
]);
}
}
}

これで areas = '1,2,3' が、バリデーション実行時には areas = [1, 2, 3] のように配列に変換された状態となり、各項目が DB に存在するかも検証できる。

その他のやり方

試してないが、getValidatorInstance を使う方法でもいけるっぽい。

まとめ

  • prepareForValidation 内でデータを変更すると幸せになれる
  • getValidatorInstance でもいけるかも(試してない)

その他・メモ

前に以下の記事を書いたが、prepareForValidation を使うともっとシンプルに書けそう。

Laravel で「開始日時 < 終了日時」であることをバリデーションする

参考文献

関連記事