フォームリクエストで起きやすい事故として true, false といった真偽値を文字列の”true”, “false”としてリクエストしてしまう自体があります。Laravel 組み込みの boolean ルールを用いて真偽値をバリデーションをすると、これがリクエストされる”true か false を指定してください”とバリデーションエラーを返すことになります。
APIを公開する場合、使う側に負担をかけずなるべく広い入力を受け取りたくなります。何をしたかったのかわかる入力がなされているのであれば、それはなおさらです。そこで Laravel の boolean ルールを拡張して文字列の”true”, “false”を真偽値として受け入れられる様にします。ちなみにフォームリクエストで真偽値相当の値を投げる時は0か1で投げるといいです。
実際に Laravel の boolean ルールに加えて文字列の”true”, “false”を許可する様にしたルールの例が次です。
<?php
namespace App\Library\Rules;
use Illuminate\Contracts\Validation\Rule;
/**
* Laravel の用意した boolean ルール に加えて 'true', 'False' の様な文字列も許可するルール
* @see https://github.com/laravel/framework/blob/c6678dcc29cef263e4021018f3174cfdc12c5c5f/src/Illuminate/Validation/Concerns/ValidatesAttributes.php#L429-L441
*/
class BooleanEasy implements Rule
{
public function passes($attribute, $value)
{
if (is_string($value)) {
// True や FALSE などの大文字小文字の違いを全て小文字にすることでなくす
$value = strtolower($value);
}
// 許可する値をリストアップ
$acceptable = [true, false, 0, 1, '0', '1', 'false', 'true'];
// 許可する値に含まれていればOK
return in_array($value, $acceptable, true);
}
public function message()
{
// Laravel の boolean のエラーメッセージをそのまま利用
return trans('validation.boolean');
}
/** このルールクラスでパスする値を bool に変換 */
public static function convertValueToBool($v): bool
{
if ($v === '0' || strtolower($v) === 'false') {
return false;
}
if ($v === '1' || strtolower($v) === 'true') {
return true;
}
return (bool) $v;
}
}
これを使って次の様にバリデーションをし、リクエストされた値を boolean 型の true, false にします。
class UserUpdateController extends \App\Http\Controllers\Controller
{
public function __invoke(\Illuminate\Http\Request $request)
{
// バリデーション。フォームリクエストを使うまでもない単純で小さなバリーションは
// コントローラーでやった方が見通しがよくなる。
$validated = $this->validate($request, [
'has_ticket' => ['required', new \App\Library\Rules\BooleanEasy()]
], [], [
'has_ticket' => 'チケットを持っているか'
]);
// バリデーション結果を boolean 型に変換
$validated['has_ticket'] = \App\Library\Rules\BooleanEasy::convertValueToBool();
// メイン処理
}
}
この様にするとより緩く入力を受け付けられます。boolean 型への変換が手間な場合はフォームリクエストのベースクラスを作り、そこから値を取り出すときに自動で変換メソッドを通る様にします。