Symfony Form ConstraintValidator和Edit / Update违规

时间:2018-04-22 17:01:49

标签: php symfony

我有一个自定义约束验证程序( @AssertUniquePhoneNumber()),用于检查客户端实体的$ phone和$ second_phone字段中是否重复了电话号码。

class Client {

    /**
     * @ORM\Column(name="phone", type="phone_number", length=50, nullable=true)
     * @AssertPhoneNumber(type="any")
     * @AssertUniquePhoneNumber()
     */
    protected $phone = null;

    /**
     * @ORM\Column(name="second_phone", type="phone_number", length=50, nullable=true)
     * @AssertPhoneNumber(type="any")
     * @AssertUniquePhoneNumber()
     */
    protected $second_phone = null;

创建新客户端时,它可以正常运行,但编辑/更新客户端时会出现问题,导致无效的电话限制违规。

这是控制器:

/**
 * @Route("/comercial/clients/edit_client/{clientId}", 
 *      requirements={"id" = "\d+"}, 
 *      defaults={"id" = 1}, 
 *      name="comercial_dashboard.clients.edit_client")
 */
public function comercialEditClient(Request $request, $clientId) {
    $repository = $this->getDoctrine()->getRepository('App:Client');
    $client = $repository->findOneById($clientId);

    if (!$client) {
        throw $this->createNotFoundException(
                'Cliente no encontrado con id ' . $clientId . '.'
        );
    }

    $form = $this->createForm(EditClientFormType::class, $client);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $client = $form->getData();
        $client->setUpdatedAt(new \DateTime('now'));
        $em = $this->getDoctrine()->getManager();
        $em->persist($client);
        $em->flush();
    }

这是验证者:

class UniquePhoneNumberValidator extends ConstraintValidator {

    private $em;

    public function __construct(EntityManagerInterface $entityManager) {
        $this->em = $entityManager;
    }

    public function validate($phoneNumber, Constraint $constraint) {

        // check if null
        if (null === $phoneNumber || '' === $phoneNumber) {
            return;
        }

        $repository = $this->em->getRepository('App:Client');
        $client = $repository->findByPhoneNumber($phoneNumber);

        if (!is_null($client)) {
            $this->context->buildViolation($constraint->message)
                    ->setParameter('{{ phoneNumber }}', $phoneNumber)
                    ->addViolation();
        }
    }
}

这是约束函数:

// unique phone number constraint function
public function findByPhoneNumber(PhoneNumber $phoneNumber) {
    $phoneUtil = PhoneNumberUtil::getInstance();

    $qb = $this->getEntityManager()->createQueryBuilder('c');
    $qb->select('c')
            ->from('App:Client', 'c')
            ->where($qb->expr()->orX(
                            $qb->expr()->eq('c.phone', ':phone'), $qb->expr()->eq('c.second_phone', ':phone')
                ))
            ->setParameter('phone', $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164))
            ->setMaxResults(1);

    return $qb->getQuery()->getOneOrNullResult();
}

如何在编辑/更新客户端时告诉应用不验证电话字段?

2 个答案:

答案 0 :(得分:1)

正如您可能也想到的那样,您的问题是,在编辑客户端实体时,您的存储库查询会返回数据库中已存在这些语音库(因为它们存储在当前编辑的内容中),因此您的验证器返回验证违规。

我的第一个答案是,这看起来像你应该使用类验证器而不是通用约束验证器,因为验证器在任何情况下都只检查客户端实体电话号码。因此,使用类验证器,您需要修改验证类&稍微注释并单独检查每个电话号码,并将实体ID传递给存储库函数以从查询中排除。

如果由于某种原因您更喜欢使用此方法,则可以从约束验证函数访问实体,因此您也可以在此处获取实体ID并将其传递给存储库函数。

public function validate($phoneNumber, Constraint $constraint) {

    // check if null
    if (null === $phoneNumber || '' === $phoneNumber) {
        return;
    }

    $currentObject = $this->context->getObject();

    $repository = $this->em->getRepository('App:Client');
    $client = $repository->findByPhoneNumber($phoneNumber, $currentObject);

    if (!is_null($client)) {
        $this->context->buildViolation($constraint->message)
                ->setParameter('{{ phoneNumber }}', $phoneNumber)
                ->addViolation();
    }
}

如上所述,无论您是使用类验证器还是通用约束验证器,都需要更新存储库函数以从搜索中排除当前客户端实体ID。

答案 1 :(得分:0)

您可以使用validation groups

在注释的约束中添加组:

/**
 * @ORM\Column(name="phone", type="phone_number", length=50, nullable=true)
 * @AssertPhoneNumber(type="any")
 * @AssertUniquePhoneNumber(groups={"creation"})
 */
protected $phone = null;

/**
 * @ORM\Column(name="second_phone", type="phone_number", length=50, nullable=true)
 * @AssertPhoneNumber(type="any")
 * @AssertUniquePhoneNumber(groups={"creation"})
 */
protected $second_phone = null;

/**
 * @ORM\Column(name="email", type="string", length=255)
 * @Assert\NotBlank(groups={"creation", "edition"})
 */
protected $email;

然后定义构建表单时用于验证的约束,这取决于您创建表单的方式。 The documentation给出了以下示例。

在控制器中:

$form = $this->createFormBuilder($users, array(
    'validation_groups' => array('creation'),
))->add(...);

在表单类中:

use Symfony\Component\OptionsResolver\OptionsResolver;

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => array('creation'),
    ));
}