空字符串验证不需要的整数

Empty string validates for not required integer

我必须验证我的 API 的输入字段,其中值必须是 1 到 100 或 null 之间的整数,或者它甚至没有设置(不需要)。

因此,我的验证规则是:'privacy_status' => "nullable|integer|min:1|max:100",

在我得到一个空字符串作为值之前,它工作正常。由于 Laravel 对空字符串的验证仅在字段为隐式时才进行验证,因此我的所有其他规则 integer, nullable or min, max 都将被忽略。

protected function isValidatable($rule, $attribute, $value)
{
    return $this->presentOrRuleIsImplicit($rule, $attribute, $value) &&
       $this->passesOptionalCheck($attribute) &&
       $this->isNotNullIfMarkedAsNullable($attribute, $value) &&
       $this->hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute);
}

protected function presentOrRuleIsImplicit($rule, $attribute, $value)
{
    if (is_string($value) && trim($value) === '') {
        return $this->isImplicit($rule);
    }

    return $this->validatePresent($attribute, $value) || $this->isImplicit($rule);
}

有没有办法正确验证这一点?

编辑

您始终可以创建自定义验证规则。

Validator::extendImplicit('fail_on_empty_string', function($attribute, $value, $parameters)
{
    return $value === "" ? false : $value;
});

您可以像这样使用新规则:

'privacy_status' => "fail_on_empty_string|nullable|integer|min:1|max:100",

旧答案

这在 Laravel 文档中有描述,并且是您自己引入的错误(尽管可能是无意识的):https://laravel.com/docs/5.6/validation#a-note-on-optional-fields:

By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. Because of this, you will often need to mark your "optional" request fields as nullable if you do not want the validator to consider null values as invalid.

空字符串会自动转换为 null,您的验证完全没问题。禁用中间件,更改它或更改您的验证规则。

您只需将 filled 规则传递给它即可。这将允许该字段可以为空,并且如果它存在于请求中;不能为空。

'privacy_policy' => 'filled|integer|min:1|max:100'

如果您想在 present 时允许空字符串,请改用 present 规则。

'privacy_policy' => 'present|nullable|integer|min:1|max:100'

更新

我添加了一个单元测试来证明它工作正常。

public function index()
{
    request()->validate([
        'privacy_policy' => 'filled|integer|min:1|max:100'
    ]);

    return response();
}

然后在测试中:

$this->get(route('test'))->assertStatus(200); // True
$this->get(route('test'), ['privacy_policy' => ''])->assertStatus(200); // False
$this->get(route('test'), ['privacy_policy' => 5])->assertStatus(200); // True