I am trying to create a custom symfony form validator constraint. I created two class, one constraint and one validator and it works fine. But I need to pass doctrine entitymanager instance to validator class, as I am using them standalone and not framework, I don't have yaml configuration file. I created a constructor in validator class to have $em, and in controller I have:
->add('email', EmailType::class, [
'constraints' => [
new Assert\Email(['message' => 'invalid.email', 'mode' => 'strict', 'normalizer' => 'trim']),
new Assert\EmailExists($em),
],
]);
But I am not getting $em, in my validator class, what should I do? I also tried to have constructor in main constraint class, then in validator I had parent::construct()
, still not working.
I did read this too How to configure dependencies on custom validator with Symfony Components? but instead of making the factory class, I used the current factor class and used this:
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;
$container = new ContainerBuilder();
$container
->register('customEmailUniqueEntity', 'EmailExistsValidator')
->addArgument($em);
$validatorBuilder = Validation::createValidatorBuilder();
$validatorBuilder->setConstraintValidatorFactory(
new ContainerConstraintValidatorFactory($container)
);
$validator = $validatorBuilder->getValidator();
$violations = $validator->validate('email address', [
new EmailExists()
]);
if (0 !== count($violations)) {
// there are errors, now you can show them
foreach ($violations as $violation) {
echo $violation->getMessage().'<br>';
}
}
With this code both dependency injection and validation works fine, but is there a trick to have this custom constraint as 'constraint' array argument within form builder rather than validating it manually?
->add('email', EmailType::class, [
'constraints' => [
new Assert\Email(['message' => 'invalid.email', 'mode' => 'strict', 'normalizer' => 'trim']),
new Assert\EmailExists($em),
],
]);
With code above I cannot pass $em to the constructor of my custom Validator. Any trick possible?
EDIT:
In order to inject doctrine EntityManager, in EmailExists
class I had:
public function validatedBy()
{
return 'customEmailUniqueEntity';
//return \get_class($this).'Validator';
}
then I had:
$container = new ContainerBuilder();
$container
->register('customEmailUniqueEntity', 'EmailExistsValidator')
->addArgument($em);
because if I was returning validator class from validatedBy()
I could not inject $em to the constructor of validator. With the answer below I used:
->addTag('validator.constraint_validator');
But now I am getting customEmailUniqueEntity
class not found error, as if I return validator from validatedBy()
, injection will not work, what should I do? I tried to return
public function validatedBy()
{
return 'EmailExists';
//return \get_class($this).'Validator';
}
but this one, of course I am getting initialize()
error. Please advise.
EDIT2:
I added addTag to:
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;
$container = new ContainerBuilder();
$container
->register('customEmailUniqueEntity', 'EmailExistsValidator')
->addArgument($em),
->addTag('validator.constraint_validator');
$validatorBuilder = Validation::createValidatorBuilder();
$validatorBuilder->setConstraintValidatorFactory(
new ContainerConstraintValidatorFactory($container)
);
$validator = $validatorBuilder->getValidator();
$violations = $validator->validate('email address', [
new EmailExists()
]);
if (0 !== count($violations)) {
// there are errors, now you can show them
foreach ($violations as $violation) {
echo $violation->getMessage().'<br>';
}
}
and in constructor of EmailExistsValidator I have:
var_dump($em);
and I got $em object in validator, so $em is injected and adding addTag()
did not cause any error. If I remove validatedBy()
of EmailExists
contsraint, injection will not be done. In that method I am doing
return `customEmailUniqueEntity;`
because if I return EmailExistsValidator
, injection will not be done.
Now how to use validator.constraint_validator
or EmailExists()
as constraints array param of the form? if I use new EmailExists()
I will get Two Few Aguments for validator class as $em wll not be injected this way. What to do?
EmailExists
constraint, but I know it should be in validator, but how to pass it to validator? β user4271704