draw/validator
PHP validation library providing a fluent API to define rules, validate arrays/inputs, and collect errors. Lightweight and framework-agnostic, suitable for Laravel or standalone apps.
Validator component, offering a structured way to enforce validation rules declaratively (via annotations, YAML, or XML). This aligns well with Laravel’s growing adoption of Symfony components (e.g., HTTP client, UX) and provides a centralized validation layer for complex business rules.Validator facade suffices for simple cases, this package introduces Symfony’s constraint system (e.g., @Assert\Callback, @Assert\Expression), which is invaluable for:
Rule objects or Validator facade extensively, the marginal benefit may not justify the complexity.validator (v6.4+) and dependency-injection components. Laravel apps using older Symfony versions (e.g., v5.x) or other Symfony packages (e.g., symfony/console) may face:
composer.json overrides or Laravel’s extra:laravel config.ValidatorInterface may conflict with Laravel’s service container bindings.validate() with Symfony’s constraints, but requires custom error mapping to Laravel’s ValidationException.ConstraintViolation objects must be translated to Laravel’s error formats (e.g., JSON responses in Sanctum/Nova).phpunit dependency may introduce conflicts with Laravel’s testing setup (e.g., Tests\TestCase vs. Symfony’s Test\WebTestCase).Validator is heavier than Laravel’s native validator. Benchmark critical paths (e.g., API endpoints) to ensure no latency spikes.ConstraintViolation objects differ from Laravel’s ValidationException, requiring custom mapping logic to maintain consistency in:
@Assert\All, @Assert\Valid), which may not align with Laravel’s conventions.validator + dependency-injection?symfony/http-foundation)?ConstraintViolation objects map to Laravel’s error responses (e.g., API JSON, Blade errors)?phpunit dependency conflict with Laravel’s testing setup?@Assert\Callback)?spatie/laravel-validation-extensions) that achieves similar goals with lower risk?required|email), Laravel’s built-in Validator is sufficient.draw/validator only for domain logic (e.g., service layer) while keeping Laravel’s validation for HTTP-boundary concerns (e.g., Form Requests).UserRegistrationService) with draw/validator constraints.ConstraintViolation objects map correctly to Laravel’s error responses.if (!preg_match(...))) with Symfony constraints in services.
use Draw\Validator\Constraints as Assert;
class Order {
#[Assert\Callback(fn (Order $order) => $order->total > 0)]
public float $total;
}
FormRequest to use the package’s validator:
public function validate() {
$validator = app(\Symfony\Component\Validator\ValidatorInterface::class);
$violations = $validator->validate($this->all());
if ($violations->count()) {
throw new \Illuminate\Validation\ValidationException($this->formatErrors($violations));
}
}
composer.json:
"extra": {
"laravel": {
"dont-discover": ["draw/validator"]
}
}
ValidatorInterface to Laravel’s container:
$this->app->bind(\Symfony\Component\Validator\ValidatorInterface::class, function ($app) {
return \Symfony\Component\Validator\Validation::createValidatorBuilder()
->enableAnnotationReading()
->getValidator();
});
AppServiceProvider:
public function register() {
$this->app->singleton(\Symfony\Component\Validator\ValidatorInterface::class, function ($app) {
return \Symfony\Component\Validator\Validation::createValidatorBuilder()
->enableAnnotationReading()
->getValidator();
});
}
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class ValidatorFacade extends Facade {
protected static function getFacadeAccessor() {
return \Symfony\Component\Validator\ValidatorInterface::class;
}
}
ConstraintViolation objects to Laravel’s format:
public function formatErrors(ConstraintViolationListInterface $violations): array {
return array_reduce($violations, function (array $errors, ConstraintViolationInterface $violation) {
$errors[$violation->getPropertyPath()][] = $violation->getMessage();
return $errors;
}, []);
}
use Draw\Validator\Constraints as Assert;
class Invoice {
#[Assert\GreaterThan(0)]
public float $amount;
#[Assert\All([new Assert\Type('string'), new Assert\Length(max: 255)])]
public string $reference;
}
FormRequest to use the package:
public function validate() {
$validator = app(\Symfony\Component\Validator\ValidatorInterface::class);
$violations = $validator->validate($this->all());
if ($violations->count()) {
throw new \Illuminate\Validation\ValidationException($this->formatErrors($violations));
}
}
How can I help you explore Laravel packages today?