Symfony-CollectionType字段中的唯一实体?

Symfony-CollectionType字段中的唯一实体?,symfony,validation,collections,constraints,unique,Symfony,Validation,Collections,Constraints,Unique,我有一个包含collectionType的formBuilder。我希望能够在电子邮件字段上设置一个约束,以确保当用户验证时,表单中多次没有相同的电子邮件地址 我已经: RegistrationCollectionType.php $builder ->add('utilisateurs', CollectionType::class, [ 'entry_type' => RegistrationType::class,

我有一个包含collectionType的formBuilder。我希望能够在电子邮件字段上设置一个约束,以确保当用户验证时,表单中多次没有相同的电子邮件地址

我已经:

RegistrationCollectionType.php

$builder
        ->add('utilisateurs', CollectionType::class, [
            'entry_type' => RegistrationType::class,
            'entry_options' => [
                'label' => false,
                'entreprise' => $entreprise,
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'delete_empty' => true,
            'by_reference' => true,
            'prototype' => true,
            'label' => false,
            'attr' => [
                'class' => 'my-selector',
                'label' => false,
            ],
            'by_reference' => false,
        ])
        ;
class RegistrationCollection
{


    private $utilisateurs = [];

    public function getUtilisateurs(): ?array
    {
        return $this->utilisateurs;
    }

    public function setUtilisateurs(?array $utilisateurs): self
    {
        $this->utilisateurs = $utilisateurs;

        return $this;
    }
}
->add('email', EmailType::class, [
                'attr' => [
                    'placeholder' => "Adresse email"
                ],
            ])
与他的班级:

RegistrationCollection.php

$builder
        ->add('utilisateurs', CollectionType::class, [
            'entry_type' => RegistrationType::class,
            'entry_options' => [
                'label' => false,
                'entreprise' => $entreprise,
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'delete_empty' => true,
            'by_reference' => true,
            'prototype' => true,
            'label' => false,
            'attr' => [
                'class' => 'my-selector',
                'label' => false,
            ],
            'by_reference' => false,
        ])
        ;
class RegistrationCollection
{


    private $utilisateurs = [];

    public function getUtilisateurs(): ?array
    {
        return $this->utilisateurs;
    }

    public function setUtilisateurs(?array $utilisateurs): self
    {
        $this->utilisateurs = $utilisateurs;

        return $this;
    }
}
->add('email', EmailType::class, [
                'attr' => [
                    'placeholder' => "Adresse email"
                ],
            ])
在与我的用户实体关联的我的RegistrationType.php中,我:

RegistrationType.php

$builder
        ->add('utilisateurs', CollectionType::class, [
            'entry_type' => RegistrationType::class,
            'entry_options' => [
                'label' => false,
                'entreprise' => $entreprise,
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'delete_empty' => true,
            'by_reference' => true,
            'prototype' => true,
            'label' => false,
            'attr' => [
                'class' => 'my-selector',
                'label' => false,
            ],
            'by_reference' => false,
        ])
        ;
class RegistrationCollection
{


    private $utilisateurs = [];

    public function getUtilisateurs(): ?array
    {
        return $this->utilisateurs;
    }

    public function setUtilisateurs(?array $utilisateurs): self
    {
        $this->utilisateurs = $utilisateurs;

        return $this;
    }
}
->add('email', EmailType::class, [
                'attr' => [
                    'placeholder' => "Adresse email"
                ],
            ])

现在,如果我有效,我已经:

SQLSTATE[23000]:完整性约束冲突:1062 du 冠军杯ahahs@mail.fr“倒酒”UNIQ_8D93D649E7927C74


您可以创建自定义验证约束

class UniqueEmailValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint instanceof UniqueEmail) {
            throw new UnexpectedTypeException($constraint, UniqueEmail::class);
        }

        if (!\is_array($value) && !$value instanceof \IteratorAggregate) {
            throw new UnexpectedValueException($value, 'array|IteratorAggregate');
        }

        $emails = [];
        foreach ($value as $element) {
            if (\in_array($element->getEmail(), $emails, true)) {
                $this->context->buildViolation($constraint->message)
                    ->addViolation();

                return;
            }

            $emails[] = $element->getEmail();
        }
    }
}
并向属性中添加验证注释

class RegistrationCollection
{

    /**
     * @AppAssert\UniqueEmailValidator
     */
    private $utilisateurs = [];

    public function getUtilisateurs(): ?array
    {
        return $this->utilisateurs;
    }

    public function setUtilisateurs(?array $utilisateurs): self
    {
        $this->utilisateurs = $utilisateurs;

        return $this;
    }
}

我保留了自定义约束的想法,但它不仅适用于电子邮件,而且适用于我们想要唯一的任何字段:

#App\Validator\Constraints\UniqueProperty.php

<?php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class UniqueProperty extends Constraint
{
    public $message = 'This collection should contain only elements with uniqe value.';
    public $propertyPath;

    public function validatedBy()
    {
        return UniquePropertyValidator::class;
    }
}
它工作得很好,只是我不能将错误定位到子字段。系统地说,错误将传递给父实体,因此错误将被全部覆盖

我尝试在验证器中重定向到相关子实体的字段,但没有做什么,错误继续将所有内容置于上面

在我的表单类型中,我尝试禁用错误\u冒泡,但事情是一样的

->add('utilisateurs', CollectionType::class, [
            'entry_type' => RegistrationType::class,
            'entry_options' => [
                'label' => false,
                'entreprise' => $entreprise,
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'delete_empty' => true,
            'by_reference' => true,
            'prototype' => true,
            'label' => false,
            'attr' => [
                'class' => 'my-selector',
                'label' => false,
            ],
            'by_reference' => false,
            'error_bubbling' => false,
        ])
        ;

谢谢你的帮助,我保留了你的想法,但是我做了一个新的回答来提供更多的细节谢谢!要将子字段作为目标
->atPath(sprintf('[%s].%s',$key,$constraint->propertyPath))
应该可以工作。