laravel-validation

Complete guide to Laravel's Validator, validation rules, Form Requests, and custom rules. Use when writing or reviewing validation logic, choosing the right validation rule, building Form Request classes, creating custom rules, or working with conditional/array/nested validation. Triggers on validate(), Validator::make(), Form Request, Rule::, Password::, File::, required, nullable, unique, exists, or any Laravel validation rule usage.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "laravel-validation" with this command: npx skills add riasvdv/skills/riasvdv-skills-laravel-validation

Laravel Validation

Always use array syntax for rules, not pipe-delimited strings. Arrays are easier to read, diff, and extend — and required when using Rule objects or closures.

// WRONG:
'email' => 'required|email|unique:users',

// CORRECT:
'email' => ['required', 'email', 'unique:users'],

Quick Decision Guide

"How do I validate?"

ScenarioApproach
Simple controller validation$request->validate([...])
Reusable/complex validationForm Request class
Outside HTTP request (CLI, jobs)Validator::make($data, $rules)
Validate and get safe data$request->safe() for ValidatedInput object
Validate but keep goingValidator::make()->validate() or check ->fails()

"Which rule do I need?"

Presence & optionality:

NeedRule
Must be present and non-emptyrequired
Required only if presentsometimes
May be nullnullable
Must be present (even if empty)present
Must not be in inputmissing
Required when other field has valuerequired_if:field,value
Required when other field is absentrequired_without:field
Exclude from validated outputexclude

Type constraints:

NeedRule
Stringstring
Integerinteger
Numeric (int, float, string)numeric
Booleanboolean
Arrayarray
Sequential list (0-indexed)list
Datedate or date_format:Y-m-d
File uploadfile
Imageimage
Emailemail
URLurl
JSONjson
UUIDuuid

Size & range:

NeedRule
Min/max length, value, count, or KBmin:n / max:n
Exact sizesize:n
Between rangebetween:min,max
Compare to another fieldgt:field / gte:field / lt:field / lte:field

Database:

NeedRule
Must exist in tableexists:table,column or Rule::exists(...)
Must be unique in tableunique:table,column or Rule::unique(...)

Validated Data Access

// Get only validated fields
$validated = $request->validated();

// Get ValidatedInput object (supports only/except/merge/etc.)
$safe = $request->safe();
$safe->only(['name', 'email']);
$safe->except(['password']);
$safe->merge(['ip' => $request->ip()]);

Common Pitfalls

1. Missing nullable on optional fields

Laravel's ConvertEmptyStringsToNull middleware converts "" to null. Without nullable, empty optional fields fail validation.

// WRONG: empty string becomes null, fails 'string' rule
'bio' => ['string', 'max:500'],

// CORRECT:
'bio' => ['nullable', 'string', 'max:500'],

2. sometimes vs nullable vs required

// required: MUST be present and non-empty
'name' => ['required', 'string'],

// nullable: can be present as null
'nickname' => ['nullable', 'string'],

// sometimes: only validate IF the field is in the input at all
// (useful for PATCH requests where fields are optional)
'email' => ['sometimes', 'required', 'email'],

3. Unsafe unique ignore

Never pass user-controlled input to ignore():

// DANGEROUS: SQL injection risk
Rule::unique('users')->ignore($request->input('id'))

// SAFE: use the authenticated model
Rule::unique('users')->ignore($user->id)

4. bail placement

bail must be the first rule to stop processing on first failure:

// WRONG: bail has no effect here
'email' => ['required', 'bail', 'email', 'unique:users'],

// CORRECT: bail first
'email' => ['bail', 'required', 'email', 'unique:users'],

5. Array vs nested validation confusion

// Validates the array itself
'tags' => ['required', 'array', 'min:1'],

// Validates each item IN the array
'tags.*' => ['string', 'max:50'],

// Nested objects in array
'users.*.email' => ['required', 'email'],
'users.*.roles.*' => ['exists:roles,name'],

6. exists / unique with soft deletes

// Ignores soft-deleted records (default counts them as existing)
Rule::unique('users', 'email')->withoutTrashed()

// Only check non-deleted records exist
Rule::exists('users', 'id')->whereNull('deleted_at')

7. Date comparison with field references

// Compare against another field, not a literal date
'end_date' => ['required', 'date', 'after:start_date'],

// Compare against a literal date
'start_date' => ['required', 'date', 'after:2024-01-01'],

// Use after_or_equal when same-day should be valid
'checkout' => ['required', 'date', 'after_or_equal:checkin'],

Rule Builders

Use fluent builders instead of string rules for complex validation. See references/rule-builders.md for the full API of every builder.

Password

use Illuminate\Validation\Rules\Password;

// Define defaults (typically in AppServiceProvider::boot)
Password::defaults(fn () => Password::min(8)->uncompromised());

// Use in rules
'password' => ['required', 'confirmed', Password::default()],

// Full chain
'password' => ['required', Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised(3)], // min 3 appearances in breach DB

File

use Illuminate\Validation\Rules\File;

'document' => ['required', File::types(['pdf', 'docx'])->max('10mb')],
'avatar' => ['required', Rule::imageFile()->dimensions(Rule::dimensions()->maxWidth(2000))],

Enum

'status' => [Rule::enum(OrderStatus::class)->except([OrderStatus::Cancelled])],

Date & Numeric

'start_date' => [Rule::date()->afterToday()->format('Y-m-d')],
'price' => [Rule::numeric()->decimal(2)->min(0)->max(99999.99)],
'email' => [Rule::email()->rfcCompliant()->validateMxRecord()],

Conditional Validation

use Illuminate\Validation\Rule;

$request->validate([
    'role' => ['required', 'string'],
    // Required only when role is admin
    'admin_code' => [Rule::requiredIf($request->role === 'admin')],

    // Using closures for complex conditions
    'company' => [Rule::requiredIf(fn () => $user->isBusinessAccount())],

    // Exclude from output when condition met
    'coupon' => ['exclude_if:type,free', 'required', 'string'],
]);

After validation hooks

$validator = Validator::make($data, $rules);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong.');
    }
});

Custom Rules

Rule object (recommended)

php artisan make:rule Uppercase
php artisan make:rule Uppercase --implicit  # runs even on empty values
class Uppercase implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail('The :attribute must be uppercase.');
        }
    }
}

// Usage
'name' => ['required', new Uppercase],

Closure rule (one-off)

'title' => [
    'required',
    function (string $attribute, mixed $value, Closure $fail) {
        if ($value === 'foo') {
            $fail("The {$attribute} is invalid.");
        }
    },
],

Custom Error Messages

// Inline
$request->validate([
    'email' => ['required', 'email'],
], [
    'email.required' => 'We need your email address.',
    'email.email' => 'That doesn\'t look like a valid email.',
]);

// In Form Request
public function messages(): array
{
    return [
        'title.required' => 'A title is required.',
        'body.required' => 'A message body is required.',
    ];
}

// Custom attribute names
public function attributes(): array
{
    return [
        'email' => 'email address',
    ];
}

// Array position placeholder
'photos.*.description.required' => 'Please describe photo #:position.',

Reference Files

  • All validation rules: See references/rules.md for every built-in rule with signatures and descriptions
  • Rule class & fluent builders: See references/rule-builders.md for Rule::unique(), Rule::exists(), Password::, File::, Rule::date(), Rule::numeric(), Rule::email(), Rule::enum(), Rule::dimensions(), and all other fluent builder APIs
  • Form Requests: See references/form-requests.md for Form Request patterns, methods, and advanced usage

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

laravel-collections

No summary provided by upstream source.

Repository SourceNeeds Review
General

OpenClaw Skill Growth

Make OpenClaw Skills observable, diagnosable, and safely improvable over time. Use this when the user wants to maintain many SKILL.md files, inspect repeated...

Registry SourceRecently Updated
171Profile unavailable
General

Find Skills for ClawHub

Search for and discover OpenClaw skills from ClawHub (the official skill registry). Activate when user asks about finding skills, installing skills, or wants...

Registry SourceRecently Updated
2871Profile unavailable
General

Skill Listing Polisher

Improve a skill's public listing before publish. Use when tightening title, description, tags, changelog, and scan-friendly packaging so the listing looks cl...

Registry SourceRecently Updated
1130Profile unavailable