Php Symfony表单约束验证器和编辑/更新冲突

Php Symfony表单约束验证器和编辑/更新冲突,php,symfony,Php,Symfony,我有一个自定义约束验证器(@AssertUniquePhoneNumber()),用于检查客户端实体的$phone和$second\u phone字段中是否重复了电话号码 class Client { /** * @ORM\Column(name="phone", type="phone_number", length=50, nullable=true) * @AssertPhoneNumber(type="any") * @AssertUniquePh

我有一个自定义约束验证器(@AssertUniquePhoneNumber()),用于检查客户端实体的$phone和$second\u 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();
    }
$form = $this->createFormBuilder($users, array(
    'validation_groups' => array('creation'),
))->add(...);
这是验证器:

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();
}

在编辑/更新客户机时,我如何告诉应用程序不要验证电话字段?

由于您可能也有困惑,您的问题是,在编辑客户机实体时,存储库查询返回这些电话号码已经存在于数据库中(因为它们是为当前编辑的条目存储的),因此您的验证器返回验证冲突

我的第一个答案是,您应该使用类验证器而不是通用约束验证器,因为您的验证器在任何情况下都只检查客户实体电话号码。因此,使用类验证器,您需要稍微修改验证类和注释,并检查每个电话号码另外,将实体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。

您可以使用

将组添加到注释中的约束:

/**
 * @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;
然后定义在构建表单时用于验证的约束,这取决于创建表单的方式。 给出以下示例

在控制器中:

/**
 * @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();
    }
$form = $this->createFormBuilder($users, array(
    'validation_groups' => array('creation'),
))->add(...);
在form类中:

use Symfony\Component\OptionsResolver\OptionsResolver;

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

也许你忘记接受上一个问题的答案了?@gp\u sflover抱歉,我不知道这个功能。它现在已经完成了。做得好,不用担心,只是提醒你要帮忙:-)谢谢,我会试试,它看起来更干净。实际上,它严格地回答了你的问题“我如何告诉应用程序在编辑时不要验证电话字段。”但您真的要禁用编辑验证吗?如果号码已更改,您仍要检查数据库中是否不存在新号码。。。