Укажите различные группы проверки для каждого элемента коллекции в Symfony 2?

[ Документация о коллекции ] При встраивании форм (тип коллекции) можно указать группы проверки для каждого элемента на основе текущего элемента? Кажется, не работает ATM.

Форма TaskType добавляет коллекцию тегов:

 // src/Acme/TaskBundle/Form/Type/TaskType.php // ... public function buildForm(FormBuilderInterface $builder, array $options) { // ... $builder->add('tags', 'collection', array( // ... 'by_reference' => false, )); } 

Например, у нас есть два тега (тег 1 и тег 2), а новый тег добавляется с помощью кнопки «Добавить» (через JavaScript):

 ----------- | add tag | ----------- - tag 1 (existing) - tag 2 (added clicking the "add tag" button) 

Тег 1 должен быть проверен по Default , Edit группы, а тег 2 – только по Default .

Форма TagType определяющая группы динамической проверки

Основываясь на базовых данных, если тег новый, он получает группу по Default , если существует значение « Default , « Create группы»:

 // ... public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'validation_groups' => function (FormInterface $form) { $tag = $form->getData(); $groups = array('Default'); if (null !== $tag && null !== $tag->getId()) { $groups[] = 'Edit'; } return $groups; } )); } // ... 

Tag с ограничением в группе «Изменить»

Пример с Tag определяющим два свойства (пропущенные аксессоры):

 class Tag { /** * @Assert\NotBlank() */ protected $name; /** * @Assert\NotBlank(groups={"Edit"}) * @Assert\Length(max="255") */ protected $description; // ... } 

Для существующего тега : описание не должно быть пустым. Для нового тега : описание может быть пустым.

Доказательная форма действительна, валидатор показывает ошибки (неверно!)

Просто отредактируйте существующий тег и оставьте описание пустым. Форма проверяется, но служба проверки достоверности показывает ошибки :

 $form = $this->createForm('task', $task) ->handleRequest($request); $validator = $this->get('validator'); if ($form->isValid()) { foreach ($task->getTags() as $tag) { // Validate against Default, Edit groups $errors = $validator->validate($tag, array('Default', 'Edit')); if (null !== $tag && null !== $tag->getId()) { echo 'Existing tag #'.$tag->getId(); } else { echo 'New tag'; } echo ', errors: '.count($errors).'<br>'; } die('Form is valid.') // ... } 

Вывод:

 Existing tag #863, errors: 1 Form is valid. 

Обновление 1 : я пробовал (без успеха) статический метод determineValidationGroups как предлагается здесь :

 public static function determineValidationGroups(FormInterface $form) { $groups = array('Default'); if ($form->getData() !== null && null !== $form->getData()->getId()) { $groups = array('Edit'); } var_dump($groups); return $groups; } 

В форме TagType :

 /** * {@inheritdoc} */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( // ... 'validation_groups' => array( 'Acme\TaskBundle\Entity\Tag', 'determineValidationGroups' ), )); } 

Результат с использованием только одного существующего тега и одного, созданного с использованием ссылки «Добавить тег», кажется правильным. Но никаких ошибок для существующего тега, оставляющего описание пустым:

 array (size=1) 0 => string 'Edit' (length=4) array (size=1) 0 => string 'Edit' (length=4) rray (size=1) 0 => string 'Default' (length=7) rray (size=1) 0 => string 'Default' (length=7) 

Полный код, который я использовал для проверки моего ответа, – https://github.com/guilro/SymfonyTests/tree/SO21276662 .

Valid сила принудительного ограничения для проверки встроенного объекта, а AFAIK API не предоставляет возможности для установки группы проверки.

Но на более высоком уровне мы можем попросить компонент Form каскадить ValidationListener ко всем внедряющим формам и использовать API-интерфейс компонента Form для установки группы проверки.

Мы должны использовать:

  • 'cascade_validation' => true в FormBuilder на всех уровнях. По умолчанию установлено значение false .
  • обратный вызов в настройках TagType для установки группы проверки. (Вы были на правильном пути.)
  • 'error_bubbling' => false , поскольку по умолчанию это верно в коллекциях

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

в TaskType.php:

 class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('tags', 'collection', array( 'type' => 'tag', 'error_bubbling' => false, 'allow_add' => true, 'by_reference' => false, 'cascade_validation' => true )) ; } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Acme\TaskBundle\Entity\Task', 'cascade_validation' => true )); } } 

в TagType.php:

 class TagType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('description', 'text', array('required' => false)); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Acme\TaskBundle\Entity\Tag', 'validation_groups' => function(FormInterface $form) { if ($form->getData() !== null && null !== $form->getData()->getId()) { return array('Edit'); } return array('Default'); }, 'error_bubbling' => false, )); } }