Я сохранил идею настраиваемого ограничения, но оно будет применяться не только к электронным письмам, но и к любому полю, которое нам нужно Уникальное:
#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 для родительского объекта, и, следовательно, ошибка будет помещена во все это.
Я пытался в валидаторе перенаправить на поля соответствующего дочернего объекта, но ничего не поделать , ошибка продолжает помещать все выше ..
В моем 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,
])
;