alikhosravidev/laravel-verbose-validator
Adds a verbose/trace mode to Laravel’s Validator to debug complex rules. Get step-by-step reports of each executed rule and its pass/fail outcome, with optional auto-enable via APP_DEBUG and configurable failure report types (failed/passed/all).
Installation:
composer require alikhosravidev/laravel-verbose-validator
Publish the config (optional):
php artisan vendor:publish --provider="AliKhosravi\VerboseValidator\VerboseValidatorServiceProvider"
Basic Usage: Replace default Laravel validation with verbose output:
use AliKhosravi\VerboseValidator\Facades\VerboseValidator;
$validator = VerboseValidator::make($data, [
'email' => 'required|email',
'password' => 'required|min:8'
]);
if ($validator->fails()) {
// Returns detailed error messages with field paths
dd($validator->errors()->all());
}
First Use Case:
Replace a standard Validator::make() call in a form request or controller:
// Before:
$validator = Validator::make($request->all(), $rules);
// After:
$validator = VerboseValidator::make($request->all(), $rules);
Form Request Integration:
Extend Illuminate\Foundation\Http\FormRequest and override failedValidation():
public function failedValidation(Validator $validator)
{
return response()->json([
'success' => false,
'errors' => VerboseValidator::make($this->all(), $this->rules())->errors()
], 422);
}
API Response Standardization: Create a base controller to wrap responses:
public function respondWithValidation($validator)
{
return response()->json([
'data' => null,
'errors' => $validator->errors(),
'status' => 'error'
], 422);
}
Dynamic Rule Generation:
Combine with Laravel's Validator::extend() for custom rules while maintaining verbose output:
Validator::extend('custom_rule', function ($attribute, $value, $parameters, $validator) {
// Custom logic
return true;
});
$validator = VerboseValidator::make($data, ['field' => 'custom_rule']);
Nested Resource Validation: Leverage nested arrays with dot notation:
$rules = [
'user.address.city' => 'required|string',
'user.address.postal_code' => 'required|digits:5'
];
App\Http\Middleware\ValidateVerbose to enforce verbose validation globally.VerboseValidator in unit tests:
$validator = $this->partialMock(VerboseValidator::class, ['make']);
$validator->shouldReceive('make')->andReturn($mockValidator);
resources/lang/en/validation.php while keeping verbose paths intact.Rule Order Sensitivity:
// May output: "user.address" instead of "user.address.city"
$rules = ['user' => 'required', 'user.address.city' => 'required'];
Custom Rule Paths:
Validator::extend()) may not inherit path context. Use Validator::replacer() to adjust:
Validator::replacer('custom_rule', function ($message, $attribute, $rule, $parameters) {
return str_replace(':attribute', 'custom_field', $message);
});
Nested Array Quirks:
present rules to filter:
$rules = ['user.*' => 'present|array', 'user.*.name' => 'required'];
Performance Overhead:
Enable Debug Mode:
Set VERBOSE_VALIDATOR_DEBUG=true in .env to log raw validation data to storage/logs/verbose-validator.log.
Path Resolution Issues:
Check config/verbose-validator.php for path_resolver options. Customize with:
'path_resolver' => \AliKhosravi\VerboseValidator\Resolvers\CustomPathResolver::class,
Custom Path Resolvers:
Implement AliKhosravi\VerboseValidator\Contracts\PathResolver to modify path generation:
class CustomPathResolver implements PathResolver {
public function resolve($attribute, $rules) {
return str_replace('.', '_', $attribute);
}
}
Error Formatter: Override the default formatter:
'error_formatter' => \App\Services\CustomVerboseFormatter::class,
Rule Presets:
Create reusable rule sets with VerboseValidator::presets():
VerboseValidator::preset('user', [
'name' => 'required|string|max:255',
'email' => 'required|email'
]);
$validator = VerboseValidator::make($data, ['user' => VerboseValidator::preset('user')]);
Conditional Rules:
Use when/unless with verbose paths:
$validator = VerboseValidator::make($data, [
'password' => ['required', 'min:8', 'confirmed'],
'password_confirmation' => ['required_with:password', 'same:password']
]);
How can I help you explore Laravel packages today?