Symfony2: Как использовать ограничения на пользовательский составной тип формы?

Вот вопрос, который я уже давно ломаю себе голову. Пожалуйста, знайте, что я не эксперт Symfony2 (пока), поэтому я мог где-то совершить новичок.

Поле 1: Стандартный Symfony2 text тип поля

Field2: тип настраиваемого поля compoundполе с text поле + checkbox поле)

предварительный просмотр

Моя цель: добавление ограничений к autoValue поле для работы на autoValue's text input child

Причина того, что ограничения не работают, вероятно, потому что NotBlank ожидает строковое значение, а внутренние данные этого поля формы являются массивом array('input'=>'value', 'checkbox' => true), Это значение массива преобразуется обратно в строку с пользовательским DataTransformer, Однако я подозреваю, что это происходит ПОСЛЕ проверки поля с известными ограничениями.

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

Мой (упрощенный) пример кода для контроллера и поля:

,

Код контроллера

Настройка быстрой формы для тестирования.

<?php
//...
// $entityInstance holds an entity that has it's own constraints 
// that have been added via annotations

$formBuilder = $this->createFormBuilder( $entityInstance, array(
    'attr' => array(
        // added to disable html5 validation
        'novalidate' => 'novalidate'
    )
));

$formBuilder->add('regular_text', 'text', array(
    'constraints' => array(
        new \Symfony\Component\Validator\Constraints\NotBlank()
    )
));

$formBuilder->add('auto_text', 'textWithAutoValue', array(
    'constraints' => array(
        new \Symfony\Component\Validator\Constraints\NotBlank()
    )
));

,

Исходные файлы TextWithAutoValue

SRC / My / Компонентный / Форма / тип / TextWithAutoValueType.php

<?php

namespace My\Component\Form\Type;

use My\Component\Form\DataTransformer\TextWithAutoValueTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class TextWithAutoValueType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('value', 'text', array(
            // when I uncomment this, the NotBlank constraint works. I just
            // want to validate against whatever constraints are added to the
            // main form field 'auto_text' instead of hardcoding them here
            // 'constraints' => array(
            //     new \Symfony\Component\Validator\Constraints\NotBlank()
            // )
        ));

        $builder->add('checkbox', 'checkbox', array(
        ));

        $builder->addModelTransformer(
            new TextWithAutoValueTransformer()
        );
    }

    public function getName()
    {
        return 'textWithAutoValue';
    }
}

SRC / My / Компонентный / Форма / DataTransformer / TextWithAutoValueType.php

<?php

namespace My\Component\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class TextWithAutoValueTransformer 
    implements DataTransformerInterface
{
    /**
     * @inheritdoc
     */
    public function transform($value)
    {
        return array(
            'value'    => (string) $value,
            'checkbox' => true
        );
    }

    /**
     * @inheritdoc
     */
    public function reverseTransform($value)
    {
        return $value['value'];
    }
}

ЦСИ / My / ComponentBundle / Ресурсы / конфигурации / services.yml

parameters:

services:
    my_component.form.type.textWithAutoValue:
        class: My\Component\Form\Type\TextWithAutoValueType
        tags:
            - { name: form.type, alias: textWithAutoValue }

ЦСИ / My / ComponentBundle / Ресурсы / мнение / Форма / fields.html.twig

{% block textWithAutoValue_widget %}
    {% spaceless %}

    {{ form_widget(form.value) }}
    {{ form_widget(form.checkbox) }}
    <label for="{{ form.checkbox.vars.id}}">use default value</label>

    {% endspaceless %}
{% endblock %}

,

Вопрос

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

-> Кто-нибудь знает, как этого добиться?

-> Для бонусных баллов; Как включить ограничения, которые были добавлены к связанной сущности главной формы? (посредством аннотаций на класс сущности)

PS

Извините, это стало таким длинным вопросом, я надеюсь, что мне удалось разъяснить мою проблему. Если нет, пожалуйста, спросите меня для более подробной информации!

2 ответа

Решение

Я предлагаю вам сначала прочитать документацию о валидации.

Из этого мы можем сделать вывод, что валидация в основном происходит на классах, а не на типах форм. Это то, что вы упустили. Что вам нужно сделать, это:

  • Чтобы создать класс данных для вашего TextWithAutoValueType, называется, например, src/My/Bundle/Form/Model/TextWithAutoValue. Он должен содержать свойства с именем text и checkbox и их установщики / получатели;
  • Чтобы связать этот класс данных с типом вашей формы. Для этого вы должны создать метод TextWithAutoValueType::getDefaultOptions() и заполнить опцию data_class. Зайдите сюда для получения дополнительной информации об этом методе;
  • Создайте проверку для вашего класса данных. Для этого вы можете использовать аннотации или файл Resources/config/validation.yml. Вместо того, чтобы связывать ваши ограничения с полями вашей формы, вы должны связать их со свойствами вашего класса:

validation.yml:

src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
            - NotBlank: ~
        checkbox:
            - Type:
                type: boolean

Редактировать:

Я предполагаю, что вы уже знаете, как использовать тип формы в другом. При определении вашей конфигурации проверки вы можете использовать очень полезную функцию, называемую группами проверки. Вот базовый пример (в файле validation.yml, так как я не очень разбираюсь в аннотациях валидации):

src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
                groups: [ Default, Create, Edit ]
            - NotBlank:
                groups: [ Edit ]
        checkbox:
            - Type:
                type: boolean

Существует параметр групп, который можно добавить к каждому ограничению. Это массив, содержащий имена групп проверки. При запросе проверки объекта вы можете указать, какой набор групп вы хотите проверить. Затем система проверит в файле проверки, какие ограничения должны быть применены.

По умолчанию группа "По умолчанию" установлена ​​для всех ограничений. Это также группа, которая используется при выполнении регулярной проверки.

  • Вы можете указать группы по умолчанию для определенного типа формы в MyFormType:: getDefaultOptions (), установив параметр validation_groups (массив строк - имена групп проверки),
  • При добавлении типа формы к другому в MyFormType::buildForm() вы можете использовать определенные группы проверки.

Это, конечно, стандартное поведение для всех опций типа формы. Пример:

$formBuilder->add('auto_text', 'textWithAutoValue', array(
    'label' => 'my_label',
    'validation_groups' => array('Default', 'Edit'),
));

Что касается использования различных объектов, вы можете накапливать свои классы данных, следуя той же архитектуре, что и ваши накопленные формы. В приведенном выше примере тип формы, использующий textWithAutoValueType, должен иметь data_class, который имеет свойство auto_text и соответствующий метод getter / setter.

В файле проверки допустимые ограничения будут иметь возможность каскадного подтверждения. Свойство с Valid обнаружит класс свойства и попытается найти соответствующую конфигурацию проверки для этого класса и применить ее с теми же группами проверки:

src/My/Bundle/Form/Model/ContainerDataClass:
    properties:
        auto_text:
            Valid: ~ # Will call the validation conf just below with the same groups

src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        ... etc

Как описано здесь https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery (слайд 39) Бернхарда Шуссека (основной разработчик расширения форм symofny), преобразователь никогда не должен изменять информацию, но только изменить его представление.

Добавляя информацию (флажок ' => true), вы делаете что-то не так.

В редактировании:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('value', 'text', $options);

    $builder->add('checkbox', 'checkbox', array('mapped'=>false));

    $builder->addModelTransformer(
        new TextWithAutoValueTransformer()
    );
}
Другие вопросы по тегам