Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validator factory #1

Merged
merged 1 commit into from
Aug 30, 2022
Merged

Conversation

ElisDN
Copy link
Contributor

@ElisDN ElisDN commented Aug 30, 2022

Кастомный валидатор работает, пока в его констуктор не передать зависимость от PHP-DI! При этом, говорит что зависимости не подтягиваются:

Too few arguments to function PhoneNumAvailableValidator::__construct(),
0 passed in vendor/symfony/validator/ConstraintValidatorFactory.php on line 43

По названию класса в тексте ошибки догадываемся, что Validator для создания объектов валидаторов ConstraintValidator использует фабрику ConstraintValidatorFactory.

Если переходим в фабрику, то там на 43 строке видим простое создание через new $className():

class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
{
    protected $validators = [];

    public function getInstance(Constraint $constraint): ConstraintValidatorInterface
    {
        $className = $constraint->validatedBy();

        if (!isset($this->validators[$className])) {
            $this->validators[$className] = 'validator.expression' === $className
                ? new ExpressionValidator()
                : new $className();
        }

        return $this->validators[$className];
    }
}

что и приводит к ошибке отсутствия передачи зависимостей.

Значит нам нужно эту фабрику подменить на другую, которая вместо new $className() будет вызывать $this->container->get($className) из переданного нами в неё контейнера.

Посмотрим, есть ли там что-то готовое? Если перейдём в интерфейс ConstraintValidatorFactoryInterface и посмотрим его реализации, то там увидим два класса:

class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface {}
class ContainerConstraintValidatorFactory implements ConstraintValidatorFactoryInterface {}

Если перейдём во второй с Container в названии, то там:

class ContainerConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
{
    private ContainerInterface $container;
    private array $validators;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
        $this->validators = [];
    }

    public function getInstance(Constraint $constraint): ConstraintValidatorInterface
    {
        $name = $constraint->validatedBy();

        if (!isset($this->validators[$name])) {
            if ($this->container->has($name)) {
                $this->validators[$name] = $this->container->get($name);
            } else {
                // ...
                $this->validators[$name] = new $name();
            }
        }

        return $this->validators[$name];
    }
}

Как раз это нам и нужно.

Значит нам нужно валидатору указать эту фабрику new ContainerConstraintValidatorFactory($container).

Валидатор мы создаём в конфиге через построитель. И там как раз находим метод setConstraintValidatorFactory:

return [
    ValidatorInterface::class => static function (ContainerInterface $container): ValidatorInterface {
        return Validation::createValidatorBuilder()
            ->enableAnnotationMapping()
            ->setTranslator($container->get(TranslatorInterface::class))
            ->setTranslationDomain('validators')
            ->setConstraintValidatorFactory(new ContainerConstraintValidatorFactory($container))
            ->getValidator();
    },
];

Теперь валидаторы будут доставаться этой фабрикой из контейнера и все зависимости заработают.

@palansher palansher merged commit da46897 into palansher:master Aug 30, 2022
@evan70
Copy link

evan70 commented Nov 18, 2022

Thanks ElisDN <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants