为了重用代码,我在一个名为ValidatorServiceProvider的文件中创建了自己的验证规则:

class ValidatorServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Validator::extend('checkEmailPresenceAndValidity', function ($attribute, $value, $parameters, $validator) {
            $user = User::where('email', $value)->first();
            
            // Email has not been found
            if (! $user) {
                return false;
            }
            
            // Email has not been validated
            if (! $user->valid_email) {
                return false;
            }
            
            return true;
        });
    }

    public function register()
    {
        //
    }
}

我是这样使用这个规则的:

public function rules()
{
    return [
        'email' => 'bail|required|checkEmailPresenceAndValidity'
    ];
}

但是,我想为每种情况设置不同的错误消息,如下所示:

if (! $user) {
    $WHATEVER_INST->error_message = 'email not found';
    return false;
}
        
if (! $user->valid_email) {
    $WHATEVER_INST->error_message = 'invalid email';
    return false;
}

But I don't figure out how to achieve this without doing 2 different rules ...
Of course it could work with multiple rules but it will also perform multiple SQL queries, and I really want to avoid that.
Also, keep in mind that in real case I could have more than 2 validations like theses in a single rule.

有人有主意吗?

=====
EDIT 1 :

Actually, I think that I want something that works in a similar way to the between or size rules.
They represent one single rule, but provide multiple error messages :

'size'                 => [
    'numeric' => 'The :attribute must be :size.',
    'file'    => 'The :attribute must be :size kilobytes.',
    'string'  => 'The :attribute must be :size characters.',
    'array'   => 'The :attribute must contain :size items.',
],

Laravel checks if the value represents a numeric, a file, a string or an array ; and gets the right error message to use.
How do we achieve this kind of thing with custom rule ?

推荐答案

不幸的是,Laravel目前没有提供一种具体的方法来直接从属性参数数组添加和调用验证规则.但这并不排除基于TraitRequest使用的潜在友好解决方案.

例如,请在下面找到我的解决方案.

第一件事是等待表单被处理,用抽象类处理表单请求.您需要做的是获取当前的Validator个实例,并防止它在出现任何相关错误时进行进一步验证.否则,将存储验证器实例,并调用稍后创建的自定义用户验证规则函数:

<?php

namespace App\Custom\Validation;

use \Illuminate\Foundation\Http\FormRequest;

abstract class MyCustomFormRequest extends FormRequest
{
    /** @var \Illuminate\Support\Facades\Validator */
    protected $v = null;

    protected function getValidatorInstance()
    {
        return parent::getValidatorInstance()->after(function ($validator) {
            if ($validator->errors()->all()) {
                // Stop doing further validations
                return;
            }
            $this->v = $validator;
            $this->next();
        });
    }

    /**
     * Add custom post-validation rules
     */
    protected function next()
    {
        
    }
}

下一步是创建Trait,它将提供验证当前验证程序实例输入的方法,并处理要显示的正确错误消息:

<?php

namespace App\Custom\Validation;

trait CustomUserValidations
{
    protected function validateUserEmailValidity($emailField)
    {
        $email = $this->input($emailField);

        $user = \App\User::where('email', $email)->first();
        
        if (! $user) {
            return $this->v->errors()->add($emailField, 'Email not found');
        }
        if (! $user->valid_email) {
            return $this->v->errors()->add($emailField, 'Email not valid');
        }

        // MORE VALIDATION POSSIBLE HERE
        // YOU CAN ADD AS MORE AS YOU WANT
        // ...
    }
}

最后,别忘了延长你的MyCustomFormRequest分钟.例如,在你的php artisan make:request CreateUserRequest之后,下面是一个简单的方法:

<?php

namespace App\Http\Requests;

use App\Custom\Validation\MyCustomFormRequest;
use App\Custom\Validation\CustomUserValidations;

class CreateUserRequest extends MyCustomFormRequest
{
    use CustomUserValidations;

    /**
     * Add custom post-validation rules
     */
    public function next()
    {
        $this->validateUserEmailValidity('email');
    }

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => 'bail|required|email|max:255|unique:users',
            'password' => 'bail|required',
            'name' => 'bail|required|max:255',
            'first_name' => 'bail|required|max:255',
        ];
    }
}

我希望你能按照我的建议来做.

Laravel相关问答推荐

Uncaught ReferenceError:未定义require[Shopify PHP React Browser问题]

如何在 Laravel 9 中获取带分页的订单列表?

验证判断请求的值是否存在于另一个表 Laravel 9 中

Laravel:在行的子集上同步多对多

导出所有客户端不起作用,文件保存时没有名称和扩展名

如何在 Laravel 中将 Select 选项表单插入数据库

Npm run dev 卡在 APP_URL

使用Laravel Blade Formatter和PHP Intelephense进行 VSCode 格式化

Laravel Eloquent 查找日期超过 2 天的行

laravel 控制器中的全局变量

如果用户在 Laravel 中经过身份验证,如何签入 Vue 组件?

如何使用 Eloquent Laravel 更新集合

Laravel 表 * 没有名为 * 的列

使用 ModelNotFoundException

约定表名(带下划线)

Laravel Eloquent ORM 复制

Laravel 字符串验证以允许空字符串

Laravel 表:只能有一个自动列,并且必须定义为键

在 Laravel 5.4 中将文件存储在公共目录和存储中的区别

复合唯一密钥验证 - laravel