Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Extravalidator Bundle Laravel Package

pugx/extravalidator-bundle

PUGXExtraValidatorBundle extends Symfony's Validator component with a set of additional, ready-to-use constraints, letting you validate common real-world data—such as locale-specific identifiers and anti-spam checks—with simple annotations or YAML rules.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle adds a handful of constraints that Symfony's core validator historically didn't ship — the classic case being "require at least N checkboxes" on multi-choice form fields. It is a thin Symfony bundle: constraint classes, validator classes, and a service definition that tags the validators with validator.constraint_validator. There is no bundle configuration to speak of, so "getting started" is really "install, register, use a constraint on a field."

1. Install (and accept the caveat)

composer require pugx/extravalidator-bundle

The package is archived. There will be no bug fixes or Symfony-version compatibility work. Pin an explicit tag/commit in composer.json so a future composer update on a fresh machine resolves the exact code you tested against.

2. Register the bundle (Symfony 2.x style)

// app/AppKernel.php
public function registerBundles()
{
    return [
        // ...
        new PUGX\ExtraValidatorBundle\PUGXExtraValidatorBundle(),
    ];
}

No config.yml entry, no extension parameters — the bundle's job is just to load its validator services.

3. Where to look first

Before writing a line of code, read the source, not the README:

  • Validator/Constraints/ — the constraint classes. This is the authoritative list of what the bundle actually offers for your pinned commit; names and option sets differ between tags.
  • Validator/ — the matching ConstraintValidator implementations. Read 2–3 of them; they tell you exact option names, default messages, and — critically — what getTargets() returns (property vs. class constraint).
  • Resources/config/ — confirm the XML/YAML service file tags each validator with validator.constraint_validator and an alias. If you later get "validator not found" errors, this file is the reason.
  • Tests/ — usually the best documentation of real usage, including edge cases (empty arrays, null values) the README omits.

4. First use case: a checkbox group with a minimum selection

use PUGX\ExtraValidatorBundle\Validator\Constraints as PugxAssert;

$builder->add('roles', 'choice', [
    'choices'  => $roles,
    'multiple' => true,
    'expanded' => true,
    'constraints' => [
        new PugxAssert\MinSelected(['min' => 2]), // verify exact class/option names in Validator/Constraints
    ],
]);

Then in the controller — the validator runs inside the normal form validation, so there is nothing extra to call:

if ($form->isValid()) {
    // ...
}

If the selected count is below the threshold, the error lands on that field and $form->get('roles')->getErrors() contains the message. That is the whole workflow: install once, then treat the constraints exactly like NotBlank or Length.

Implementation Patterns

Attach constraints in the form type, not in entity mapping. These constraints are form-shaped (checkbox counts, field comparisons). Keeping them in FormType::buildForm() means they can't accidentally fire during entity persistence or API deserialization, where "at least 2 roles selected" may be a UI rule rather than a domain invariant.

Use class-level constraints for cross-field rules. If the constraint's validator returns Constraint::CLASS_CONSTRAINT from getTargets(), it must be attached to the object, not the field:

$builder->add('startDate', 'date')
        ->add('endDate', 'date');

$resolver->setDefaults([
    'constraints' => [new PugxAssert\DateAfter(['firstField' => 'startDate', 'secondField' => 'endDate'])],
]);

Attaching a class-level constraint to a property throws a ConstraintDefinitionException at mapping time — that's your signal you picked the wrong target.

Reuse via a shared form-type base or trait. Projects typically end up applying the same checkbox/date rule across several forms. Wrap them:

trait ExtraValidatorConstraints
{
    protected function minSelection($min)
    {
        return new PugxAssert\MinSelected(['min' => $min]);
    }
}

This also gives you one place to swap the implementation when you migrate off the bundle.

Drive behaviour with validation groups. Extra constraints are a natural fit for multi-step wizards and partial saves:

$form = $this->createForm(MyType::class, $data, ['validation_groups' => ['Default', 'publish']]);

Put the strict rules (minimum selections, date ordering) in a publish group so drafts can be saved half-filled and only the final submit enforces them.

Test constraints directly, not through the form. Instantiate the validator service and call validate() with a crafted value. In a Symfony 2-era codebase, extend the bundle's/validator's ConstraintValidatorTest base class; this is dramatically faster than booting a kernel and submitting a form, and it pins the behaviour you rely on if you later replace the constraint with a core one.

Treat it as a library of examples as much as a dependency. Each constraint is ~30 lines: a Constraint subclass with public options and messages, plus a validator with isValid(). Copying the pattern into your own AppBundle\Validator\Constraints for the next bespoke rule is often better than adding another vendor dependency — you get the same behaviour with no archived-package risk.

Gotchas and Tips

Archived means frozen in the Symfony 2 era. Expect friction on Symfony 3+ (constraint API removals, setDefaultOption/getDefaultOption deprecations becoming removals, AbstractConstraintValidator/ConstraintValidator naming changes, service tag and validator.constraint_validator alias behaviour). If the bundle installs but validators are never invoked, suspect class-name/API drift before suspecting your form. Do not upgrade Symfony "around" this bundle silently — verify each constraint with a unit test.

Replace rather than revive where core now covers you. Most of the bundle's value has been absorbed by Symfony core:

  • Minimum/maximum selections on multiple choice fields → Count (with min/max) or Choice with min/max options.
  • Numeric comparisons → GreaterThan, LessThan, Range.
  • Cross-field rules → a Callback constraint on the class, or Expression.
  • Conditional/derived rules → Expression.

A short deprecation sweep replacing each bundle constraint with its core equivalent removes the dependency entirely, which is almost always the right call for a 16-star archived package.

Empty values are usually skipped. Like core constraints, most validators return early on null/''/[]. A required checkbox group submitted with nothing checked may therefore bypass a "min selected" rule silently. Pair the extra constraint with NotBlank (or NotNull) and test the empty-submit path explicitly — this is the single most common production bug with selection-count validators.

Check the default message parameters and translation domain. Messages often interpolate {{ limit }}-style parameters. If a message renders with a literal {{ limit }}, your options key doesn't match what the validator reads (min vs limit vs count). Also confirm the messages are translatable in your locale; the bundle may ship a Resources/translations/validators.* file covering only a few languages, in which case you override in app/Resources/translations/validators.en.yml.

Debug the wiring before debugging the logic. To confirm the validators are registered as services:

# Symfony 2.x / 3.x
app/console debug:container --tag=validator.constraint_validator
# Symfony 4+
bin/console debug:container --tag=validator.constraint_validator

If the alias is missing, the constraint's validatedBy() will resolve to nothing and you'll get an RuntimeException about a validator not being found. Note this is a runtime failure on first validation, not a boot-time failure — tests that never hit that constraint won't catch it.

Inspect errors properly. $form->getErrors() only returns errors attached at that level. For a class-level constraint, errors land on the form root, not the field:

foreach ($form->getErrors(true) as $error) {
    echo $error->getOrigin()->getName() . ': ' . $error->getMessage();
}

Extension point: write your own, don't patch vendor code. The clean extension path is to add your own validator service tagged validator.constraint_validator with a unique alias — the bundle doesn't need to know about it, and your rule survives when the bundle is eventually removed. Never edit vendor/pugx/...; the next composer install eats it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment