使用带有附加参数的自定义规则验证 Laravel 中的数组

Posted

技术标签:

【中文标题】使用带有附加参数的自定义规则验证 Laravel 中的数组【英文标题】:Validating array in Laravel using custom rule with additional parameter 【发布时间】:2019-07-24 14:42:24 【问题描述】:

我正在使用 Laravel 5.7,我需要使用 2 个输入(前缀+数字)来验证电话长度。总位数必须始终为 10。

我正在将此自定义规则用于其他工作正常的项目:

<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;

class PhoneLength implements Rule

    public $prefix;

/**
 * Create a new rule instance.
 *
 * @return void
 */
public function __construct($prefix = null)

    //
    $this->prefix = $prefix;


/**
 * Determine if the validation rule passes.
 *
 * @param  string  $attribute
 * @param  mixed  $value
 * @return bool
 */
public function passes($attribute, $value)

    //
    return strlen($this->prefix)+strlen($value) == 10 ? true : false;


/**
 * Get the validation error message.
 *
 * @return string
 */
public function message()

    return 'El Teléfono debe contener 10 dígitos (prefijo + número)';


在我的控制器中,我做了类似的事情

$validatedData = $request->validate([
  'prefix' => 'integer|required',
  'number' => ['integer','required', new PhoneLength($request->prefix)],
]);

现在我需要使用数组,所以我的新验证看起来像

$validatedData = $request->validate([
  'phones.*.prefix' => 'required',
  'phones.*.number' => ['required', new PhoneLength('phones.*.prefix')],
]);

上面的代码根本不起作用,参数没有按预期发送。 如何发送数组值?当然我需要从同一个数组元素中获取值,所以如果phones[0].number正在验证中,则需要前缀phones[0].prefix

我发现了这个问题,但我拒绝相信这是不可能以“原生”方式完成的: Laravel array validation with custom rule

提前致谢

【问题讨论】:

【参考方案1】:

您可以从请求本身获得$prefix

class PhoneLength implements Rule

    public function passes($attribute, $value)
    
        $index = explode('.', $attribute)[1];
        $prefix = request()->input("phones.$index.prefix");
    

或者在PhoneLength规则构造函数中传递$request,然后使用它。

【讨论】:

【参考方案2】:

Abdeldayem Sherif 的回答很好,但是当属性嵌套层次较多时就会出现问题,例如:clients.*.phones.*.prefix。在这种情况下,爆炸和使用1 索引将导致意外错误。更好的解决方案是使用str_replace

class PhoneLength implements Rule

    public function passes($attribute, $value)
    
        $prefixAttr = str_replace('.number', '.prefix', $attribute);
        $prefix = request()->input($prefixAttr);
    

【讨论】:

【参考方案3】:

根据您可以使用的https://github.com/laravel/framework/pull/18654,它会将您的自定义规则添加为依赖项,并将 asterix 替换为所需的索引

Validator::extendDependent('contains', function ($attribute, $value, $parameters, $validator) 
   // The $parameters passed from the validator below is ['*.provider'], when we imply that this
   // custom rule is dependent the validator tends to replace the asterisks with the current
   // indices as per the original attribute we're validating, so *.provider will be replaced
   // with 0.provider, now we can use array_get() to get the value of the other field.

    // So this custom rule validates that the attribute value contains the value of the other given
    // attribute.
    return str_contains($value, 
            array_get($validator->getData(), $parameters[0])
    );
);


Validator::make(
    [['email' => 'test@mail.com', 'provider' => 'mail.com']],
    ['*.email' => 'contains:*.provider']
)->validate();

【讨论】:

以上是关于使用带有附加参数的自定义规则验证 Laravel 中的数组的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 验证:存在附加列条件 - 自定义验证规则

Laravel 验证规则的自定义错误消息:维度

Laravel 中正则表达式规则的自定义验证消息?

如何使唯一数组的自定义验证规则依赖于其他字段 laravel

Laravel 5.5 的自定义验证对象/类

Laravel Spark 中的自定义验证消息