Mr Pablo
Mr Pablo

Reputation: 4187

Symfony2 - How to use Entity variables in CallbackValidator?

I have a form built with some custom validators and they work like a charm, but I am having trouble adding in a new validator that works slightly different to the others.

Basically I need to check data from the form against a value I can usually extract from an Entity.

In this case, I need to grab the users password salt ( using $user->getSalt() ). the problem seems to be that the CallbackValidator class cannot accept any other data, other than $form.

My code:

    $user = $this->get('security.context')->getToken()->getUser();

    $form = $this->createFormBuilder($user)
            ->add('password', 'password')
            ->add('newPassword', 'password', array('label' => 'New Password', 'property_path' => false))
            ->add('confirmPassword', 'password', array('label' => 'Confirm Password', 'property_path' => false))
            ->addValidator(new CallbackValidator(function($form)
            {
                $encoder = new MessageDigestPasswordEncoder('sha1', false, 1);
                $password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

                if($password != $user->getPassword()) {
                    $form['password']->addError(new FormError('Incorrect password'));
                }
                if($form['confirmPassword']->getData() != $form['newPassword']->getData()) {
                    $form['confirmPassword']->addError(new FormError('Passwords must match.'));
                }
                if($form['newPassword']->getData() == '') {
                    $form['newPassword']->addError(new FormError('Password cannot be blank.'));
                }
            }))
            ->getForm();

Now, this is the error I get:

Fatal error: Call to a member function getSalt() on a non-object in /Sites/src/UserBundle/Controller/DashboardController.php on line 57

Line 57 being:

$password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

I have tried various things to try and pass the salt to the CallbackValidator and so far the only way is to add it into the form as a hiddne field BUT this is not acceptable as it is a security risk and I would also need to add the hashed password as a hidden field in order to match the input against.

There must be a simpler way to do this?

Upvotes: 1

Views: 1683

Answers (1)

Florian Klein
Florian Klein

Reputation: 8915

Your $user variable coming from $this->get('security.context')->getToken()->getUser(); is not defined in the scope of the anonymous function.

Contrary to languages like javascript that inherits from parent scope (automatic closure), you need to ask explicitly php to do it. The use keyword is especially made for that: http://php.net/manual/en/functions.anonymous.php

$user = new User;
function($form) use($user) { 

};

Here is a better explanation :) Javascript closures vs PHP closures, what's the difference?

So all you should have to do is modify your code like that:

$user = $this->get('security.context')->getToken()->getUser();

$form = $this->createFormBuilder($user)
        ->add('password', 'password')
        ->add('newPassword', 'password', array('label' => 'New Password', 'property_path' => false))
        ->add('confirmPassword', 'password', array('label' => 'Confirm Password', 'property_path' => false))
        ->addValidator(new CallbackValidator(function($form) use($user)
        {
            $encoder = new MessageDigestPasswordEncoder('sha1', false, 1);
            $password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

            if($password != $user->getPassword()) {
                $form['password']->addError(new FormError('Incorrect password'));
            }
            if($form['confirmPassword']->getData() != $form['newPassword']->getData()) {
                $form['confirmPassword']->addError(new FormError('Passwords must match.'));
            }
            if($form['newPassword']->getData() == '') {
                $form['newPassword']->addError(new FormError('Password cannot be blank.'));
            }
        }))
        ->getForm();

Upvotes: 6

Related Questions