Francisco Albert
Francisco Albert

Reputation: 1711

Validator with Doctrine dependency Injection in Symfony

I'm trying to validate a field "email" in a signup form. I don't want duplicate emails. For this I need to use Doctrine inside my custom validator. I know I have to define this dependency as a service in the DI container.

After reading some doc I couldn't yet. I have this now:

Validation.yml

...
  properties:
    email:
      - NotBlank: ~
      - Email:    ~
      - Cgboard\SignupBundle\Validator\Constraints\EmailDoesntExist: ~
...

config.yml

services:
  validator.unique.EmailDoesntExist:
    class: Cgboard\SignupBundle\Validator\Constraints\EmailDoesntExistValidator
    tags:
      - { name: validator.constraint_validator, alias: EmailDoesntExistValidator }

EmailDoesntExistValidator.php

...
public function validate($value, Constraint $constraint)
{
    $em     = $this->get('doctrine')->getEntityManager(); // save our entity in DB
    $result = $em->getRepository('CgboardSignupBundle:User')->userExist($value);

    if (empty($result)) {
        return true;
    }

    $this->context->addViolation($constraint->message, array());
    return false;
}
...

I'm stuck, anything would help me (example in internet or whatever)...thanks!

Upvotes: 3

Views: 6726

Answers (4)

Michaël Perrin
Michaël Perrin

Reputation: 6238

You should use the UniqueEntity constraint (http://symfony.com/doc/current/reference/constraints/UniqueEntity.html) provided with Symfony.

...
    constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: email
    properties:
        email:
            - NotBlank: ~
            - Email: ~

Would you need a more specific constraint, use a validator declared as a service as you did, and inject the Doctrine entity manager into it.

Upvotes: 2

tomazahlin
tomazahlin

Reputation: 2167

I agree with what ponciste wrote. Your validator is not a service by default, as you write it. You define it as a service, the way ponciste wrote, but please do not put that in config.yml. Instead put it in services.yml inside a bundle, where your validator class lives. You can inject EntityManager that way, or and other service which already has Entity Manager injected.

Another way and I believe a more simple way would be to this inside validation.yml:

Project\Bundle\UserBundle\Entity\User: constraints: - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: fields: [email] message: 'person.email.already_used'

...

If you have any question or problem, just comment;)

Upvotes: 2

ponciste
ponciste

Reputation: 2229

Try to inject the EntityManager this way (in config.yml):

email_doesnt_exist_validator:
    class: Cgboard\SignupBundle\Validator\Constraints\EmailDoesntExistValidator
    arguments:
        - "@doctrine.orm.entity_manager"

Then you have to set it as class attribute:

class EmailDoesntExistValidator {

   private $em;

   public function __construct(EntityManager $em) { // i guess it's EntityManager the type
       $this->em = $em;
   }

   // here you should be able to access the EntityManager
   public function validate($value, Constraint $constraint){
       $result = $this->em->getRepository('Cgboard\SignupBundle:User')->userExist($value);

       // ...
   }
}

I wrote the code right here, I hope it works, anyway this should be the right approach!

Upvotes: 4

ElPoney
ElPoney

Reputation: 125

You can see a realy great example on the CookBook : http://symfony.com/doc/current/cookbook/validation/custom_constraint.html

Can you show us your constraint class? Because you need one to make it work. And your validator.yml, to be sure you are correctly referencing your constraint class.

By the way you dont need to return something in your function validate(), if the value dont addViolation, it will be considered ok.

Upvotes: 2

Related Questions