n7/symfony-validators-bundle
A Symfony bundle that brings Laravel-style validators to Symfony applications, offering reusable validation rules, service integration, and a familiar API for validating form and request data with minimal configuration.
Treat this package as unaudited until you've read it. Zero stars, zero dependents, a single recent release (2025-06-26) and a score of 0.06 mean there is no community signal — only the source tells you what it does. Before composer require, open the repo and read, in this order:
composer.json — confirm "type": "symfony-bundle" and the symfony/* version constraints. This tells you immediately whether it will even install on your app.src/DependencyInjection/*Extension.php and Resources/config/services.* — what services are registered, what tags they carry, whether anything is autowired or made public.src/ constraint and validator classes — the actual value proposition.README.md and tests/ — usage examples and whether the advertised behaviour is covered.Then install and register:
composer require n7/symfony-validators-bundle
# Symfony Flex usually appends to config/bundles.php automatically
php bin/console debug:container --tag=validator.constraint_validator
That last command is your fastest read on the bundle: it lists every custom validator it registered. If the list is empty, the bundle either registers nothing or forgot to tag its services (see Gotchas).
First use case: pick the single constraint that motivated the install, attach it to a DTO, and validate that DTO through #[MapRequestPayload] in a controller. That exercises the constraint class, the validator service, the DI wiring and the message translation in one pass — if that works end to end, the rest of the bundle is likely fine.
If you're coming from Laravel: the bundle itself will not boot outside Symfony's kernel. What you actually want is the constraint classes. See the bridging pattern below.
Attribute constraints on DTOs. The canonical Symfony 6.4/7 flow works unchanged:
final class RegisterUser
{
#[Assert\NotBlank]
#[Assert\Email]
public string $email = '';
#[SomeBundleConstraint] // the reason you installed this
public string $vatId = '';
}
public function __invoke(#[MapRequestPayload] RegisterUser $dto): Response { ... }
Custom validators with dependencies. If the bundle ships validators that hit a repository or HTTP client, they must be services tagged validator.constraint_validator. Check whether the bundle tags them for you; if it doesn't, add the tag yourself rather than duplicating the class:
App\Validator\VatIdValidator:
tags: [{ name: validator.constraint_validator, alias: 'app.vat_id' }]
Validation groups per context. Reuse one DTO for create and update with #[Assert\GroupSequence(['Default', 'Strict'])] or validation_groups: ['registration']. This is where bundles usually add value — they often register their own groups, so run php bin/console debug:validator App\Dto\RegisterUser after wiring to confirm which constraints actually fire.
Composite constraints. If a bundle constraint delegates to other constraints internally, prefer that over hand-chaining Assert\All/Assert\Collection. It keeps the violation paths consistent and gives you one message key to translate.
Bridging into Laravel (the realistic use for a Laravel dev). Skip the bundle; install symfony/validator and reuse the constraint classes you need:
// AppServiceProvider::register()
$this->app->singleton(ValidatorInterface::class, fn ($app) =>
Validation::createValidatorBuilder()
->enableAttributeMapping()
->setConstraintValidatorFactory(new ContainerConstraintValidatorFactory($app))
->getValidator()
);
Then wrap it in a Rule that maps violations to $fail():
public function validate(string $attribute, mixed $value, Closure $fail): void
{
foreach ($this->validator->validate($value, $this->constraints) as $violation) {
$fail($violation->getMessage());
}
}
Use it in a FormRequest's rules() as [new SymfonyConstraintRule([...])], or in after() when you need the whole payload validated as one object.
Testing. Validation::createValidatorBuilder()->enableAttributeMapping() covers constraints with no dependencies. For validators that need services, boot a KernelTestCase or instantiate the validator directly and attach it — this doubles as a contract test that catches a silent behaviour change on upgrade.
The risk is the dependency, not the code. Zero dependents means no one has found the edge cases for you. Pin the exact version ("n7/symfony-validators-bundle": "1.x.y"), read the full diff once, and consider copying the two or three constraints you need into src/Validator behind your own namespace. A 300-line constraint is cheaper to own than an unmaintained transitive dependency.
The bundle does nothing in Laravel. symfony-bundle type packages rely on the kernel's bundle extension to load services. In Laravel you get the classes only — any validator that injects a bundle-defined service will fail. Check each constraint's validator constructor before assuming it ports.
"Too few arguments to function ...::__construct()" is the classic symptom of an untagged constraint validator: Symfony's ConstraintValidatorFactory falls back to new and your injected dependency is missing. Fix with the tag above, then re-run debug:container --tag=validator.constraint_validator.
Check the Symfony version constraint before you plan. A 2025 release may target ^7.0 only, which rules out LTS apps on 6.4. composer why-not n7/symfony-validators-bundle 1.0.0 answers this faster than reading composer.json.
Messages and translations. Constraint message strings resolve against the validators translation domain. If the bundle ships Resources/translations/validators.*, verify the keys are actually present for your locale; if not, add your own with the same keys rather than overriding at the call site.
Silent failures are common. A constraint that is never reached produces no error. When something "passes" suspiciously, dump the constraint list (debug:validator) rather than the violations, and confirm the group you're validating contains the constraint you expect.
Extension points if you need to change behaviour. Override the bundle's service definitions in your own config/services.yaml, decorate ConstraintValidatorFactory to swap a validator, or implement PrependExtensionInterface to adjust the bundle's config before it loads. All three keep you off a fork — which matters a lot when the upstream has no maintainer to merge your PR.
Add composer audit and a contract test now. With one release and no users, an upgrade is unverified. A single test asserting the violation codes for your most important constraint is cheap insurance.
How can I help you explore Laravel packages today?