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()
);
}