Laravel validation based on a variable

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel Validation: How to Check for Uniqueness Using Validated Data

As a senior developer working with Laravel, one of the most common challenges we face is ensuring data integrity—specifically enforcing uniqueness constraints before data hits the database. When handling form submissions, developers often use the built-in validation system, but it's crucial to understand the difference between input validation (checking format and presence) and business logic validation (checking relational constraints like uniqueness).

The scenario you presented—validating if an establishment_code is unique using data derived from $validatedData—is a perfect example of where standard validation rules fall short, and we need to implement custom logic.

The Limitation of Standard Validation Rules

When you use $request->validate(), you are defining rules that check the incoming request data against simple criteria (e.g., required, string, max:20). These rules operate purely on the HTTP request payload itself. They cannot inherently query the database to determine if a value already exists in the establishments table.

Your current approach of checking uniqueness after validation, as shown in your example, is functional but separates the business logic from the validation pipeline. To make this process cleaner, more robust, and truly "Laravel-like," we should aim to integrate this check directly into the validation flow.

Method 1: The Robust Solution – Custom Validation Rules

The most idiomatic Laravel way to handle complex uniqueness checks is by creating a custom validation rule. This keeps your controller logic clean and centralizes the uniqueness definition within the validation layer itself.

Step 1: Create the Custom Rule

You would typically create a rule that uses Eloquent queries to check for existence. For this example, let's assume you place this in a service or a dedicated app/Rules directory.

// app/Rules/UniqueCodeRule.php
namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\Rule;
use App\Models\Establishment; // Assuming your model is named Establishment

class UniqueCodeRule implements Rule
{
    protected $column;

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

    /**
     * Run the validation rule.
     *
     * @param  \Closure(string): \Illuminate\TranslationRuledate  $fail
     */
    public function passes($attribute, $value)
    {
        // Check if any record exists with this code
        return !Establishment::where($this->column, $value)->exists();
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute ('.ucwords($this->column).') is already in use.';
    }
}

Step 2: Apply the Rule in Your Request

Now, you incorporate this rule into your request validation. When using a custom rule, Laravel automatically handles the execution flow, ensuring that if the rule fails, the entire validation process stops immediately.

// In your Request class or Controller method setup:
public function establishment_insert(Request $request)
{
    $validatedData = $request->validate([
        'name' => 'required|max:190',
        'code' => 'required|max:2|unique:establishments', // Standard unique check (if you use Eloquent relationship uniqueness)
        'district_id' => 'required|max:20',
    ]);

    // If we want to be extremely explicit or handle complex logic, 
    // we can still run the custom check on $validatedData if needed, 
    // but for simple uniqueness, the built-in `unique` rule is often sufficient.
    
    // The true power comes when you define rules that interact with your models.
    
    // ... rest of the insertion logic
}

Method 2: Integrating Logic Post-Validation (Refining Your Current Approach)

If creating a custom rule seems overkill for this single check, you can refine your existing approach to ensure $validatedData is used consistently. The key here is to perform the database check immediately after validation and use that result to determine success or failure before proceeding with the insert.

In your original code, you correctly extracted $establishment_code. You can integrate this back into a single, atomic operation:

public function establishment_insert(Request $request)
{
    // 1. Validate the structure and basic rules first
    $validatedData = $request->validate([
        'name' => 'required|max:190',
        'code' => 'required|max:2',
        'district_id' => 'required|max:20',
    ]);

    // 2. Prepare the data for checking (using validated data)
    $establishment_code = strtoupper($validatedData['code']);

    // 3. Perform the uniqueness check against the database
    $check = Establishment::where('code', $establishment_code)->first();

    if ($check) {
        // If a duplicate is found, return an error immediately
        return redirect('establishments/' . $validatedData['district_id'])
                         ->withErrors(['code' => 'Establishment code already exists!']);
    } else {
        // 4. Insert only if the check passes
        Establishment::create($validatedData);
        return redirect('establishments/' . $validatedData['district_id'])->with('success', 'Establishment created successfully!');
    }
}

Conclusion: Prioritizing Data Integrity

While both methods achieve the goal, Method 1 (Custom Validation Rules) is preferred in large, complex applications because it adheres to the principle of "fail fast." By pushing relational integrity checks into the validation layer, you ensure that invalid data never reaches your business logic or database operations. Always strive for elegant separation of concerns; use Eloquent relationships and custom rules to keep your controllers focused on orchestrating workflow rather than performing intricate data lookups. For deeper dives into building robust data layers in Laravel, exploring advanced features available through the Laravel framework is highly recommended.