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
}
}