mcpField
L
laravel-validation-patterns

laravel-validation-patterns

github.com/iserter开发48100 次安装27 周前更新
代码仓库

关于 laravel-validation-patterns

Laravel Validation Patterns 为实现 Laravel 请求验证的开发者提供参考模式,涵盖 Form Request、自定义规则、条件与嵌套验证、数据库规则,以及安全使用已验证数据。

主要功能

  1. 01Form Request 类的模式
  2. 02可复用的自定义规则对象
  3. 03条件与嵌套验证
  4. 04数据库和枚举规则
  5. 05安全访问已验证数据

适用场景

  1. 01将验证逻辑移出控制器
  2. 02验证嵌套请求数组
  3. 03应用带范围限制的唯一性检查
  4. 04在控制器中仅使用已验证输入

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/iserter/laravel-claude-agents --skill laravel-validation-patterns

安装后在 Claude Code 中输入/laravel-validation-patterns确认已加载。

详细介绍

Laravel 验证模式

表单请求类(标准方法)

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class StoreOrderRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', Order::class);
    }

    public function rules(): array
    {
        return [
            'customer_id' => ['required', 'exists:customers,id'],
            'items' => ['required', 'array', 'min:1'],
            'items.*.product_id' => ['required', 'exists:products,id'],
            'items.*.quantity' => ['required', 'integer', 'min:1'],
            'notes' => ['nullable', 'string', 'max:500'],
        ];
    }

    public function messages(): array
    {
        return [
            'items.required' => 'At least one item is required.',
            'items.*.product_id.exists' => 'Product #:position does not exist.',
        ];
    }

    protected function prepareForValidation(): void
    {
        $this->merge([
            'notes' => strip_tags($this->notes),
            'email' => strtolower($this->email),
        ]);
    }

    public function after(): array
    {
        return [
            function (\Illuminate\Validation\Validator $validator) {
                if ($this->hasExceededOrderLimit()) {
                    $validator->errors()->add('items', 'You have exceeded the daily order limit.');
                }
            },
        ];
    }
}

自定义规则对象

<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class StrongPassword implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (! preg_match('/[A-Z]/', $value)) {
            $fail('The :attribute must contain at least one uppercase letter.');
        }

        if (! preg_match('/[0-9]/', $value)) {
            $fail('The :attribute must contain at least one number.');
        }
    }
}

// Usage in rules
'password' => ['required', 'string', 'min:8', new StrongPassword],

条件验证

public function rules(): array
{
    return [
        'type' => ['required', Rule::in(['individual', 'company'])],

        // Required only when type is company
        'company_name' => ['required_if:type,company', 'string', 'max:255'],

        // Excluded when type is individual (not present in validated data)
        'tax_id' => ['exclude_if:type,individual', 'required', 'string'],

        // Dynamic conditional rule
        'billing_address' => [
            Rule::when($this->boolean('different_billing'), ['required', 'string']),
        ],

        // Conditional with sometimes (only validates if field is present)
        'coupon_code' => ['sometimes', 'string', 'exists:coupons,code'],
    ];
}

数组和嵌套验证

public function rules(): array
{
    return [
        'tags' => ['required', 'array', 'min:1', 'max:10'],
        'tags.*' => ['string', 'max:50'],

        'items' => ['required', 'array'],
        'items.*.name' => ['required', 'string'],
        'items.*.options' => ['sometimes', 'array'],
        'items.*.options.*.key' => ['required_with:items.*.options', 'string'],
    ];
}

数据库规则

public function rules(): array
{
    return [
        // Unique with ignore (for updates)
        'email' => [
            'required',
            'email',
            Rule::unique('users')->ignore($this->user()),
        ],

        // Unique with scoping
        'slug' => [
            'required',
            Rule::unique('posts')->where('tenant_id', $this->user()->tenant_id),
        ],

        // Exists with additional constraints
        'category_id' => [
            'required',
            Rule::exists('categories', 'id')->where('active', true),
        ],
    ];
}

枚举验证

use App\Enums\OrderStatus;

public function rules(): array
{
    return [
        'status' => ['required', Rule::enum(OrderStatus::class)],

        // Only allow specific enum values
        'priority' => [
            'required',
            Rule::enum(Priority::class)->only([Priority::High, Priority::Critical]),
        ],
    ];
}

处理已验证的数据

// In controller
public function store(StoreOrderRequest $request)
{
    // ✅ Use validated data only
    $validated = $request->validated();

    // ✅ Use safe() for partial access
    $orderData = $request->safe()->only(['customer_id', 'notes']);
    $items = $request->safe()->except(['notes']);

    // ✅ Merge additional trusted data
    $order = Order::create(
        $request->safe()->merge(['user_id' => $request->user()->id])->all()
    );

    // ❌ Never use unvalidated input
    $order = Order::create($request->all());

    // ❌ Never bypass validation
    $order = Order::create($request->input());
}

常见陷阱

// ❌ Validating inline in controllers
public function store(Request $request)
{
    $request->validate(['title' => 'required']);
    // Hard to test, not reusable
}

// ✅ Use Form Request classes
public function store(StorePostRequest $request)
{
    Post::create($request->validated());
}

// ❌ Missing bail - continues validating after first failure
'email' => ['email', 'unique:users', 'dns_check'],

// ✅ Use bail to stop on first failure
'email' => ['bail', 'email', 'unique:users'],

// ❌ Using $request->all() instead of validated data
Order::create($request->all());

// ✅ Only validated and safe data
Order::create($request->validated());

检查清单

  • 验证逻辑应放在表单请求类中,而不是控制器中
  • authorize() 方法应正确检查权限
  • 使用自定义规则对象实现可复用的复杂验证
  • prepareForValidation() 应在验证前清理输入
  • 使用 after() 进行跨字段或业务逻辑验证
  • 使用通配符表示法验证数组和嵌套字段
  • 数据库规则应使用适当的作用域和忽略模式
  • 创建或更新模型时,只使用已验证的安全数据
  • 在需要提前终止时使用 bail
  • 为面向用户的字段提供自定义错误消息

评论

支持 Markdown