Symfony - Уникальный объект в поле CollectionType? - PullRequest
0 голосов
/ 12 января 2020

У меня есть formBuilder, который содержит collectionType. Я хотел бы иметь возможность наложить ограничение на поле электронной почты, чтобы быть уверенным, что при проверке пользователя несколько раз не будет одного и того же адреса электронной почты в форме

I'm:

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,
        ])
        ;

Со своим классом:

RegistrationCollection. php

class RegistrationCollection
{


    private $utilisateurs = [];

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

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

        return $this;
    }
}

И в моем RegistrationType. php, который связан с моей Пользователь сущностью, у меня есть:

RegistrationType. php

->add('email', EmailType::class, [
                'attr' => [
                    'placeholder' => "Adresse email"
                ],
            ])

enter image description here

Теперь, если я действую, у меня есть:

SQLSTATE [23000]: нарушение ограничения целостности : 1062 Duplicata du champ 'ahahs@mail.fr' cle la clef 'UNIQ_8D93D649E7927C74'

Ответы [ 2 ]

1 голос
/ 13 января 2020

Я сохранил идею настраиваемого ограничения, но оно будет применяться не только к электронным письмам, но и к любому полю, которое нам нужно Уникальное:

#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;
    }
}

и

#App\Validator\Constraints\UniquePropertyValidator.php

<?php

namespace App\Validator\Constraints;

use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

class UniquePropertyValidator extends ConstraintValidator
{
    /**
     * @var \Symfony\Component\PropertyAccess\PropertyAccessor
     */
    private $propertyAccessor;

    public function __construct()
    {
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
    }

    /**
     * @param mixed $value
     * @param Constraint $constraint
     * @throws \Exception
     */
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint instanceof UniqueProperty) {
            throw new UnexpectedTypeException($constraint, UniqueProperty::class);
        }

        if (null === $value) {
            return;
        }

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

        if ($constraint->propertyPath === null) {
            throw new \Exception('Option propertyPath can not be null');
        }

        $propertyValues = [];
        foreach ($value as $key => $element) {
            $propertyValue = $this->propertyAccessor->getValue($element, $constraint->propertyPath);
            if (in_array($propertyValue, $propertyValues, true)) {

                $message = sprintf("%s (%s)", $constraint->message, $propertyValue);

                $this->context->buildViolation($message)
                    // ->atPath(sprintf('[%s]', $key))
                    ->atPath(sprintf('[%s][%s]', $key, $constraint->propertyPath))
                    ->addViolation();
            }

            $propertyValues[] = $propertyValue;
        }
    }
}

и

class RegistrationCollection
{


    /**
     * @App\UniqueProperty(
     *      message = "Adresse mail déjà utilisée",
     *      propertyPath = "email"
     * )
     *
     */
    private $utilisateurs = [];

Это работает очень хорошо, за исключением того, что я не могу указать дочернее поле для ошибки. Систематически, ошибка будет go для родительского объекта, и, следовательно, ошибка будет помещена во все это.

Я пытался в валидаторе перенаправить на поля соответствующего дочернего объекта, но ничего не поделать , ошибка продолжает помещать все выше ..

enter image description here

enter image description here

В моем FormType I попытался отключить error_bubbling но тоже самое

->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,
        ])
        ;
0 голосов
/ 13 января 2020

Вы можете создать пользовательское ограничение проверки

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...