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

ero*_*onn 2 collections validation constraints unique symfony

我有一个包含 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,
        ])
        ;
Run Code Online (Sandbox Code Playgroud)

与他的班级:

注册集合.php

class RegistrationCollection
{


    private $utilisateurs = [];

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

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

        return $this;
    }
}
Run Code Online (Sandbox Code Playgroud)

在与我的User实体关联的RegistrationType.php中,我:

注册类型.php

->add('email', EmailType::class, [
                'attr' => [
                    'placeholder' => "Adresse email"
                ],
            ])
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

SQLSTATE[23000]:违反完整性约束:1062 Duplicata du champ 'ahahs@mail.fr' pour la clef 'UNIQ_8D93D649E7927C74'

ero*_*onn 5

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

\n\n
#App\\Validator\\Constraints\\UniqueProperty.php\n\n<?php\n\nnamespace App\\Validator\\Constraints;\n\nuse Symfony\\Component\\Validator\\Constraint;\n\n/**\n * @Annotation\n */\nclass UniqueProperty extends Constraint\n{\n    public $message = \'This collection should contain only elements with uniqe value.\';\n    public $propertyPath;\n\n    public function validatedBy()\n    {\n        return UniquePropertyValidator::class;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
#App\\Validator\\Constraints\\UniquePropertyValidator.php\n\n<?php\n\nnamespace App\\Validator\\Constraints;\n\nuse Symfony\\Component\\PropertyAccess\\PropertyAccess;\nuse Symfony\\Component\\Validator\\Constraint;\nuse Symfony\\Component\\Validator\\ConstraintValidator;\nuse Symfony\\Component\\Validator\\Exception\\UnexpectedTypeException;\nuse Symfony\\Component\\Validator\\Exception\\UnexpectedValueException;\n\nclass UniquePropertyValidator extends ConstraintValidator\n{\n    /**\n     * @var \\Symfony\\Component\\PropertyAccess\\PropertyAccessor\n     */\n    private $propertyAccessor;\n\n    public function __construct()\n    {\n        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();\n    }\n\n    /**\n     * @param mixed $value\n     * @param Constraint $constraint\n     * @throws \\Exception\n     */\n    public function validate($value, Constraint $constraint)\n    {\n        if (!$constraint instanceof UniqueProperty) {\n            throw new UnexpectedTypeException($constraint, UniqueProperty::class);\n        }\n\n        if (null === $value) {\n            return;\n        }\n\n        if (!\\is_array($value) && !$value instanceof \\IteratorAggregate) {\n            throw new UnexpectedValueException($value, \'array|IteratorAggregate\');\n        }\n\n        if ($constraint->propertyPath === null) {\n            throw new \\Exception(\'Option propertyPath can not be null\');\n        }\n\n        $propertyValues = [];\n        foreach ($value as $key => $element) {\n            $propertyValue = $this->propertyAccessor->getValue($element, $constraint->propertyPath);\n            if (in_array($propertyValue, $propertyValues, true)) {\n\n                $message = sprintf("%s (%s)", $constraint->message, $propertyValue);\n\n                $this->context->buildViolation($message)\n                    // ->atPath(sprintf(\'[%s]\', $key))\n                    ->atPath(sprintf(\'[%s][%s]\', $key, $constraint->propertyPath))\n                    ->addViolation();\n            }\n\n            $propertyValues[] = $propertyValue;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
class RegistrationCollection\n{\n\n\n    /**\n     * @App\\UniqueProperty(\n     *      message = "Adresse mail d\xc3\xa9j\xc3\xa0 utilis\xc3\xa9e",\n     *      propertyPath = "email"\n     * )\n     *\n     */\n    private $utilisateurs = [];\n
Run Code Online (Sandbox Code Playgroud)\n\n

它工作得很好,只是我无法将错误定位到子字段。系统地,错误将转到父实体,因此错误将被全部覆盖。

\n\n

我尝试在验证器中重定向到相关子实体的字段,但无济于事,错误继续将所有内容放在上面。

\n\n

在此输入图像描述

\n\n

在此输入图像描述

\n\n

在我的 FormType 中,我尝试禁用error_bubbling但同样的事情

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