Laravel Scene-Based Validation Implementation

To implement scene-based validation in Laravel, begin by creating a base validator class that supports conditional rule application based on predefined scenarios.

<?php
namespace Modules\Common\Validation;

use Illuminate\Support\Facades\Validator;

class BaseValidator
{
    protected array $rules = [];
    protected array $messages = [];
    protected array $scenes = [];
    protected ?string $activeScene = null;
    protected array $errors = [];
    protected array $fieldsToValidate = [];

    public function forScene(string $name): static
    {
        $this->activeScene = $name;
        return $this;
    }

    public function validate(array $data, array $rules = [], array $messages = [], string $scene = ''): bool
    {
        $this->errors = [];

        $rules = $rules ?: $this->rules;
        $messages = $messages ?: $this->messages;

        if (!$this->resolveScene($scene)) {
            return false;
        }

        if (!empty($this->fieldsToValidate)) {
            $filteredRules = [];
            foreach ($this->fieldsToValidate as $field) {
                if (isset($rules[$field])) {
                    $filteredRules[$field] = $rules[$field];
                }
            }
            $rules = $filteredRules;
        }

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

        if ($validator->fails()) {
            $this->errors = $validator->errors()->first();
            return false;
        }

        return true;
    }

    protected function resolveScene(string $scene = ''): bool
    {
        $sceneName = $scene ?: $this->activeScene;
        $this->fieldsToValidate = [];

        if (empty($sceneName)) {
            return true;
        }

        if (!isset($this->scenes[$sceneName])) {
            $this->errors = "Scene '{$sceneName}' is not defined.";
            return false;
        }

        $definition = $this->scenes[$sceneName];
        $this->fieldsToValidate = is_string($definition) 
            ? explode(',', $definition) 
            : $definition;

        return true;
    }

    public function getErrors(): mixed
    {
        return $this->errors;
    }
}

Next, extend this base class to define specific validation logic:

<?php
namespace Modules\Common\Validation;

class UserValidator extends BaseValidator
{
    protected array $rules = [
        'username' => 'required|max:6',
        'password' => 'required',
    ];

    protected array $messages = [
        'username.required' => 'Username is required.',
        'username.max'      => 'Username must not exceed 6 characters.',
        'password.required' => 'Password is required.',
    ];

    protected array $scenes = [
        'create' => ['username', 'password'],
        'update' => ['username', 'password'],
        'delete' => ['username'],
    ];
}

Finally, use the validator in a controller:

use Modules\Common\Validation\UserValidator;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $input = $request->only(['username', 'password']);
        $validator = new UserValidator();

        if (!$validator->forScene('create')->validate($input)) {
            return response()->json([
                'error' => $validator->getErrors()
            ], 422);
        }

        // Proceed with creation logic
    }
}

Tags: laravel Validation PHP scene-based-validation form-validation

Posted on Tue, 12 May 2026 15:55:02 +0000 by Bobo the Bugbear