Laravel 自定义验证规则的验证规则的依赖注入策略与验证逻辑的条件分支方法

🚀 Laravel 自定义验证规则的依赖注入策略与验证逻辑的条件分支方法:一场轻松愉快的技术讲座

大家好!👋 欢迎来到今天的 Laravel 技术讲座。今天我们要聊的是一个既有趣又实用的话题——如何在 Laravel 中自定义验证规则,并通过依赖注入和条件分支来优化验证逻辑。如果你是一个喜欢追求代码优雅和可维护性的开发者,那这篇文章绝对不容错过!


🔍 背景:为什么要自定义验证规则?

Laravel 的验证系统非常强大,内置了许多常用的验证规则(比如 requiredemail 等)。然而,在实际开发中,我们经常会遇到一些复杂的业务需求,这些需求可能无法通过内置规则直接满足。这时,我们就需要创建 自定义验证规则

举个例子:假设你正在开发一个在线商城系统,要求用户输入的邮政编码必须符合特定国家的格式。这种情况下,内置的 regex 规则可能不够灵活,我们需要一个更智能的解决方案。


🛠️ 自定义验证规则的基本方式

在 Laravel 中,有三种常见的自定义验证规则的方式:

  1. 使用闭包 (Closure)
    最简单的方式是直接在验证规则中使用匿名函数。

    Validator::make($data, [
       'zip_code' => [
           'required',
           function ($attribute, $value, $fail) {
               if (!preg_match('/^d{5}(-d{4})?$/', $value)) {
                   $fail('The :attribute format is invalid.');
               }
           },
       ],
    ]);

    优点:快速简单。
    缺点:复用性差,代码冗长。

  2. 扩展 Validator 类
    可以通过 Validator::extend 方法为全局添加一个新的验证规则。

    Validator::extend('valid_zip_code', function ($attribute, $value, $parameters, $validator) {
       return preg_match('/^d{5}(-d{4})?$/', $value);
    });

    使用时:

    Validator::make($data, [
       'zip_code' => ['required', 'valid_zip_code'],
    ]);

    优点:全局可用,易于复用。
    缺点:难以进行单元测试,且不易管理复杂逻辑。

  3. 创建独立的 Rule 对象
    推荐的方式是使用 Laravel 提供的 Rule 类,创建一个独立的验证类。

    use IlluminateContractsValidationRule;
    
    class ValidZipCode implements Rule
    {
       public function passes($attribute, $value)
       {
           return preg_match('/^d{5}(-d{4})?$/', $value);
       }
    
       public function message()
       {
           return 'The :attribute format is invalid.';
       }
    }

    使用时:

    use AppRulesValidZipCode;
    
    Validator::make($data, [
       'zip_code' => ['required', new ValidZipCode()],
    ]);

    优点:高复用性、易测试、结构清晰。
    缺点:稍微多写一点代码。


💡 验证规则的依赖注入策略

在实际项目中,验证规则往往需要依赖外部服务或数据源。例如,邮政编码的验证可能需要调用一个第三方 API 来确认其有效性。这时,我们可以利用 依赖注入 来增强验证规则的功能。

示例:依赖注入实现邮政编码验证

假设我们需要通过一个外部服务 ZipCodeService 来验证邮政编码的有效性。

步骤 1:创建服务类

namespace AppServices;

class ZipCodeService
{
    public function isValid($zipCode): bool
    {
        // 假设这里调用了一个外部 API
        return in_array($zipCode, ['10001', '90210']);
    }
}

步骤 2:修改 Rule 类以支持依赖注入

use IlluminateContractsValidationRule;
use AppServicesZipCodeService;

class ValidZipCode implements Rule
{
    protected $zipCodeService;

    public function __construct(ZipCodeService $zipCodeService)
    {
        $this->zipCodeService = $zipCodeService;
    }

    public function passes($attribute, $value)
    {
        return $this->zipCodeService->isValid($value);
    }

    public function message()
    {
        return 'The :attribute format is invalid.';
    }
}

步骤 3:注册服务并使用 Rule

AppServiceProvider 或其他服务提供者中绑定 ZipCodeService

$this->app->singleton(ZipCodeService::class, function () {
    return new ZipCodeService();
});

然后在控制器中使用:

use AppRulesValidZipCode;
use AppServicesZipCodeService;

public function store(Request $request, ZipCodeService $zipCodeService)
{
    $validated = $request->validate([
        'zip_code' => ['required', new ValidZipCode($zipCodeService)],
    ]);

    // 其他逻辑...
}

🌟 验证逻辑的条件分支方法

有时候,验证规则需要根据上下文动态变化。例如,某些字段只有在特定条件下才需要验证。Laravel 提供了多种工具来实现这种需求。

方法 1:使用 sometimes 方法

sometimes 方法允许我们在特定条件下应用验证规则。

$validator = Validator::make($data, [
    'zip_code' => 'nullable',
]);

if ($data['country'] === 'US') {
    $validator->sometimes('zip_code', 'required|valid_zip_code');
}

方法 2:结合 whenunless 方法

从 Laravel 8 开始,FormRequest 支持 whenunless 方法,用于动态调整验证规则。

return [
    'zip_code' => [
        'nullable',
        Rule::when($this->input('country') === 'US', [
            'required',
            new ValidZipCode(),
        ]),
    ],
];

方法 3:自定义条件分支逻辑

如果需要更复杂的条件分支,可以直接在 passes 方法中实现逻辑判断。

class ValidZipCode implements Rule
{
    protected $country;

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

    public function passes($attribute, $value)
    {
        if ($this->country === 'US') {
            return preg_match('/^d{5}(-d{4})?$/', $value);
        }

        return true; // 其他国家不验证
    }

    public function message()
    {
        return 'The :attribute format is invalid for the selected country.';
    }
}

📝 总结

今天我们一起探讨了 Laravel 自定义验证规则的核心技巧,包括依赖注入和条件分支的实现方法。以下是关键点的总结表:

方法 优点 缺点
使用闭包 快速简单 复用性差
扩展 Validator 类 全局可用,易于复用 难以测试,不易管理复杂逻辑
创建独立的 Rule 对象 高复用性、易测试、结构清晰 略微多写一点代码

希望这篇文章能帮助你在实际项目中更好地应用 Laravel 的验证系统!如果有任何问题,欢迎在评论区留言 😊。

下次见!👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注