仅当字段值存在时,Symfony 2才会验证

时间:2014-08-14 07:47:44

标签: php validation symfony

我在Symfony2中遇到验证系统问题。我有一个帐户实体,经过注册和帐户更新验证。该实体具有用户名,密码,姓名,电子邮件等。在“帐户更新”屏幕上,我允许更新帐户的用户名和密码。我希望只有输入一个值才能在帐户上更新密码,这样可以很好地实现,但验证失败,因为Validator需要密码。如果我使用密码和帐户注册一个单独的组而没有密码,则根本不会对其进行验证。我希望它只在那里输入新密码时才能验证。在这种情况下是否可以进行条件验证?

1 个答案:

答案 0 :(得分:2)

要在验证表单中添加一些逻辑,过程非常简单。您可以将callable传递给'validation_groups'OptionsResolverInterface。

示例(来自Symfony2书):

use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function(FormInterface $form) {
            $data = $form->getData();
            if (Entity\Client::TYPE_PERSON == $data->getType()) {
                return array('person');
            } else {
                return array('company');
            }
        },
    ));
}

或者:

use Symfony\Component\OptionsResolver\OptionsResolverInterface;

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => array(
            'Acme\AcmeBundle\Entity\Client',
            'determineValidationGroups',
        ),
    ));
}

退房:http://symfony.com/doc/current/book/forms.html#groups-based-on-the-submitted-data

修改1

试试这个:

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function(FormInterface $form) {
            $account = $form->getData();
            $password = $account->getPassword();
            if (!empty($password)) {
                return array('group_with_password');
            } else {
                return array('group_without_password');
            }
        },
    ));
}

编辑2

您可以使用表单事件Symfony2 [1]。事件Symfony \ Component \ Form \ FormEvents :: PRE_SUBMIT在为用户对象设置之前为您提供数组上的数据。

一种好方法是使用另一个属性(未映射到数据库)来存储用户键入的密码。像这样:

<?php

/**
 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User {

    /**
     * @var integer
     * 
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * The password encrypted.
     * @var string
     *
     * @ORM\Column(type="text", nullable=true)
     */
    protected $password;

    /**
     * Password in plain text. This field should not be mapped as Doctrine field.
     * 
     * @var string
     */
    protected $plainPasword;
}

$ plainPassword用于用户可以设置/更改密码的表单中。除非用户更改密码,否则此属性始终为null。

$ password用于存储$ plainPassword的加密版本。该属性将存储在数据库中。

要知道何时给出新密码,只需检查控制器/服务中的$ plainPassword。查看示例住所:

/**
 *
 * @Route("user/{id}", name="user_update")
 * @Method("POST")
 * @Template()
 */
public function updateAction(Request $request, $id)
{
    $em = $this->getDoctrine()->getManager();
    $user = $em->getRepository('MyBundle:User')->find($id);


    if (!$user) {
        throw $this->createNotFoundException('Unable to find User entity.');
    }

    $editForm = $this->createEditForm($user);
    $editForm->handleRequest($request);

    if ($editForm->isValid()) {
        $user = $editForm->getData();
        $newPassword = $user->getPlainPassword();

        if (!empty($newPassword)) {
            $encodeFactory = $this->get('security.encoder_factory');
            $passwordEncoder = $factory->getEncoder($user);
            $encodedPassword = $encoder->encodePassword($newPassword, $user->getSalt());
            $user->setPassword($encodedPassword);
        }

        $em->persist($user);
        $em->flush();

        return $this->redirect($this->generateUrl('user_show', array('id' => $id)));
    }

    return array(
        'entity'      => $user,
        'edit_form'   => $editForm->createView(),
    );
}

为了简短和说教,我将所有逻辑都放在控制器中,但最好将它们移到服务中。这是FOSUserBundle做的方式[2] [3]。

[1] http://symfony.com/doc/current/components/form/form_events.html

[2] https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php

[3] https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php