You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel自定义必填验证规则:可选字段兼容nullable问题求解

问题描述

需求是允许用户从数据库中选择字段的必填/可选属性。已自定义RequiredRule,当字段标记为必填且值为空时验证失败,该规则对必填字段生效正常。但可选字段会出现“The field must be string”错误——因为未设置nullable,若添加nullable则自定义规则又会被忽略。需要实现:非必填字段自动视为nullable,同时不影响自定义必填规则的生效。

当前验证规则:

'name' => [
    new RequiredRule(),
    'string',
],

RequiredRule代码:

namespace App\Rules;

use Closure;
use App\Models\RuleTable;
use Illuminate\Contracts\Validation\ValidationRule;

final class RequiredRule implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $attribute = RuleTable::query()->where('field', $attribute)->first();
        
        if ($attribute->required && empty($value)) {
            $fail("The {$attribute->display_name} field is required.");
        }
    }
}
解决方案

有几种可行的解决办法:

方法一:动态构建验证规则(推荐)

先从数据库读取字段的必填配置,再动态生成规则集合,确保非必填字段的空值不会触发字符串验证:

// 查询当前字段的配置
$fieldConfig = \App\Models\RuleTable::where('field', 'name')->first();

// 初始化规则数组
$rules = [new \App\Rules\RequiredRule()];

if ($fieldConfig->required) {
    // 必填字段直接验证字符串格式
    $rules[] = 'string';
} else {
    // 非必填字段允许空值,仅当字段有值时才验证字符串
    $rules[] = 'nullable';
    $rules[] = 'sometimes:filled';
    $rules[] = 'string';
}

// 执行验证
$request->validate(['name' => $rules]);

方法二:用内置规则替代自定义RequiredRule

如果可以替换自定义规则,直接用Laravel内置的requiredIf结合闭包读取数据库配置,搭配nullable和sometimes:filled实现需求:

use Illuminate\Validation\Rule;

$rules = [
    'name' => [
        Rule::requiredIf(function () {
            return \App\Models\RuleTable::where('field', 'name')->value('required');
        }),
        'nullable',
        'sometimes:filled',
        'string',
    ],
];

$request->validate($rules);

方法三:修改自定义Rule处理空值字段

调整RequiredRule的逻辑,当非必填字段为空时,直接从请求中移除该字段,让后续的string规则因字段不存在而自动跳过:

// 修改后的RequiredRule
namespace App\Rules;

use Closure;
use App\Models\RuleTable;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\Request;

final class RequiredRule implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $field = RuleTable::query()->where('field', $attribute)->first();
        
        if ($field->required && empty($value)) {
            $fail("The {$field->display_name} field is required.");
        } elseif (!$field->required && empty($value)) {
            // 移除空值的非必填字段,后续规则不再验证
            app(Request::class)->offsetUnset($attribute);
        }
    }
}

验证规则保持不变即可:

'name' => [
    new RequiredRule(),
    'string',
],

内容的提问来源于stack exchange,提问作者Jagdish Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:35:37