5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel のバリデーションルール exists に Eloquent を使う v2

Posted at

以前に書いた Laravel のバリデーションルール exists に Eloquent を使うの強化版です

背景

以前書いた記事ではカラムやその値の無意識化を目的に、コンストラクタでモデル名を受け取り、存在をクエリするカスタムバリデーションルールを定義しました。

$this->modelName::where($this->propertyName, $value)->exists()

しかし、この解決策には次の問題がありました

  • 渡された値と DB 上の値の型が一致しないと SQL エラーになる場合がある
  • 整数の場合に負数を渡してもクエリが走る

ルールをいくつか追加すると解決できますが、複数のエラーは出せないなどアプリの仕様に影響する、カラムやその値の無意識化を目的としているので避けたいところです。

'id' => [
    'required',
    'integer',
    'min:1', // 主キーのカラムは 1 以上
    'max:2147483647', // 主キーのカラムは DB の integer の範囲
    'bail', // どこかで失敗したら Exists はバリデートしない
    new Exists(Hoge::class),
],

標準の exists では例外的に他のルールで失敗したらバリデートはしない対応をしているようです。
カスタムバリデーションルールでは他のルールの失敗を得られないため、別の対応が必要そうです。

新しい解決策

悩んだうえ、できた新しいルールのソースコードが次
ほとんど主キーで探すことが多いので、対象を integer の主キーに絞ることで解決を図りました。

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class ExistsKey implements Rule
{
    protected $modelName;

    const INTEGER_MAX = 2147483647;

    public function __construct(string $modelName)
    {
        $this->modelName = $modelName;
    }

    public function passes($attribute, $value)
    {
        // 整数でないときはバリデートしない。エラーは別のルールで出す。
        if (validator(['value' => $value], ['value' => 'integer'])->fails()) {
            return true;
        }

        if ($value < 1 || $value > self::INTEGER_MAX) {
            return false;
        }

        return $this->modelName::whereKey($value)->exists();
    }

    public function message()
    {
        return ':attribute はデータが存在しません';
    }
}

使い方

リクエストで渡された値がモデルの主キーとして存在するか調べます。

use App\Hoge;
use App\Rules\ExistsKey;
'hoge_id' => [
    'required',
    'integer',
    new ExistsKey(Hoge::class), // これ
],

追伸

使ってみるとそこそこ使えますが、対象を主キーに絞ったので、主キー以外のカラムで調べるときは別にクエリして調べる必要があります。

また内部的には整数であるかのバリデーションを 2 回することになります。
もっといい方法はないものか。

5
4
0

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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?