Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

Symfony version(s) affected

5.4

Description

Inject a dependency in a custom validator results in a dependency injection error.

How to reproduce

  • Create a custom constraint


<?php

declare(strict_types=1);

namespace Service\Adapter\Framework\Validator\Constraint;

use Attribute;
use Service\Adapter\Framework\Validator\Validator\GtinCheckDigitConstraintValidator;

#[Attribute]
class GtinCheckDigitConstraint extends CustomConstraint
{
    public string $message = 'validation.identity.gtin.digit';

    public function validatedBy(): string
    {
        return GtinCheckDigitConstraintValidator::class;
    }
}
  • Create a custom validator for it with a Logger in the constructor
<?php

declare(strict_types=1);

namespace Service\Adapter\Framework\Validator\Validator;

use Psr\Log\LoggerInterface;
use Real\Validator\Gtin\Factory;
use Real\Validator\Gtin\NonNormalizable;
use Service\Adapter\Framework\Validator\Constraint\GtinCheckDigitConstraint;
use Service\Domain\Mapper\ValidationErrorCodeMapper;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

class GtinCheckDigitConstraintValidator extends ConstraintValidator
{
    public function __construct(
        private readonly LoggerInterface $logger
    ) {
    }

    public function validate($value, Constraint $constraint): void
    {
        $this->logger->info('Test text...');

        if (!$constraint instanceof GtinCheckDigitConstraint) {
            throw new UnexpectedTypeException($constraint, GtinCheckDigitConstraint::class);
        }

        try {
            Factory::create($value);
        } catch (NonNormalizable) {
            $this
                ->context
                ->buildViolation($constraint->message)
                ->setCode(ValidationErrorCodeMapper::CUSTOM_IDENTITY_GTIN_CHECK_DIGIT_ERROR)
                ->addViolation();
        }
    }
}
  • Then add the configuration in services.yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true

  Service\Adapter\Framework\Validator\Validator\GtinCheckDigitConstraintValidator:
    arguments:
      $logger: '@logger'
  • Create a test or a simple controller that use this validator. The error looks like this
ArgumentCountError : Too few arguments to function Service\Adapter\Framework\Validator\Validator\GtinCheckDigitConstraintValidator::__construct(), 0 passed in /var/www/vendor/symfony/validator/ConstraintValidatorFactory.php on line 43 and exactly 1 expected

Possible Solution

No response

Additional Context

No response

You must be logged in to vote

Replies: 2 comments · 8 replies

Comment options

I don't know how you construct the ConstraintValidatorFactory in your test, but if your validator class uses dependency injection, you need to bootstrap the factory similarly to how it's done in a Symfony application. The FrameworkBundle for example gives you an instance of ContainerConstraintValidatorFactory.

You must be logged in to vote
8 replies
@LauLaman
Comment options

Hi @juanwilde Did you manage to get this fixed?

I thought i ran in to the same problem.. In my case it was a Case mismatch between loaded and declared class names.

CustomThing vs CustomthingValidator

Once i resolved that Di started to work.

@juanwilde
Comment options

Hi @LauLaman. The problem in the end was that we were injecting ValidatorInterfaceFactory into a service to create a new ValidatorInterface implementation into a service and this was failing. Instead, we just created the property classes with PHP attributes with the rules and then inject ValidatorInterface in our service. If you want, plase paste your configuration and dependency injection logic and I will try to find if our issue is there :)

@BooleanType
Comment options

I had the same error, but the reason was that I accidentally added the #[Attribute] attribute to the validator class also, not only to the constraint class. Moreover, this error was in the code for quite a long time, but for some reason it showed up only after updating Symfony to version 7.3.

@zpottie
Comment options

I had the same error, but the reason was that I accidentally added the #[Attribute] attribute to the validator class also, not only to the constraint class. Moreover, this error was in the code for quite a long time, but for some reason it showed up only after updating Symfony to version 7.3.

Same here, removing the Attribute from the validator class seemed to fix it - thanks for the tip!

@martattacks
Comment options

I had the same error, but the reason was that I accidentally added the #[Attribute] attribute to the validator class also, not only to the constraint class. Moreover, this error was in the code for quite a long time, but for some reason it showed up only after updating Symfony to version 7.3.

Good grief. Thank you. I was losing my mind. 🙏

Comment options

I would check two separate things here.

First, the common gotcha: make sure the PHP #[Attribute] is on the constraint class, not on the validator class. The validator should be a normal service; the constraint is the metadata object used as an attribute.

The shape should be:

#[\Attribute]
final class MyConstraint extends Constraint
{
}

and:

final class MyConstraintValidator extends ConstraintValidator
{
    public function __construct(private SomeService $service) {}

    public function validate(mixed $value, Constraint $constraint): void
    {
        // use $this->service here
    }
}

Second, the validator factory in your test/app must come from the container. In a full Symfony app, ContainerConstraintValidatorFactory handles this. In a standalone/unit setup, if you instantiate the validator factory manually, Symfony cannot inject services into the validator.

So the rule of thumb is:

  • constraint/attribute: lightweight metadata
  • validator: service with dependencies
  • tests: use the container-backed validator factory when DI matters
You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
7 participants
Converted from issue

This discussion was converted from issue #53697 on January 31, 2024 11:20.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.