Symfony2: Как использовать ограничения для типа настраиваемых составных форм?
Вот вопрос, над которым я уже давно ломаю голову.
Пожалуйста, знайте, что я не эксперт Symfony2 (пока), поэтому я мог бы совершить ошибку новобранец где-то.
Поле1: стандартный тип поля Symfony2 text
Поле2: поле поля настраиваемого поля compound
с полем text
поле + checkbox
)
![preview]()
Моя цель: Получение ограничений, добавленных в поле autoValue
для работы с autoValue text input child
Причина, по которой ограничения не работают, вероятно, потому что NotBlank
ожидает строковое значение, а внутренние данные этого поля формы - это массив array('input'=>'value', 'checkbox' => true)
. Это значение массива преобразуется обратно в строку с пользовательским DataTransformer
. Однако я подозреваю, что это происходит ПОСЛЕ проверки правильности поля с известными ограничениями.
Как вы видите ниже в комментированном коде, мне удалось получить ограничения, работающие над текстовым вводом, однако только тогда, когда они жестко закодированы в виде формы autoValue, и я хочу проверить его на основные ограничения поля.
Мой (упрощенный) пример кода для контроллера и поля:
.
Код контроллера
Настройка быстрой формы для целей тестирования.
<?php
//...
// $entityInstance holds an entity that has it 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/Component/Форма/тип/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'];
}
}
SRC/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 %}
.
Вопрос
Я читаю документы и Google уже довольно много часов и не могу понять, как копировать, связывать или ссылаться на исходные ограничения, которые были добавлены при создании этой формы.
- > Кто-нибудь знает, как это сделать?
- > Для бонусных очков; как включить ограничения, которые были добавлены в связанную сущность главной формы? (через аннотации в классе сущностей)
PS
Извините, что это был такой длинный вопрос, я надеюсь, что мне удалось сделать мою проблему понятной. Если нет, просьба уточнить подробности!
Ответы
Ответ 1
Я предлагаю вам сначала прочитать документацию о проверке.
Что мы можем сделать из этого, так это то, что валидация прежде всего происходит на классах, а не на типах форм. Это то, что вы упустили. Что вам нужно сделать:
- Чтобы создать класс данных для TextWithAutoValueType, например, src/My/Bundle/Form/Model/TextWithAutoValue. Он должен содержать свойства, называемые текстом и флажком и их установщиками/получателями;
- Связать этот класс данных с типом формы. Для этого вы должны создать метод 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
Edit:
Я предполагаю, что вы уже знаете, как использовать тип формы в другом. При определении конфигурации проверки вы можете использовать очень полезное, называемое группы проверки. Вот базовый пример (в файле validation.yml, так как я недостаточно разбираюсь в аннотации проверки):
src/My/Bundle/Form/Model/TextWithAutoValue:
properties:
text:
- Type:
type: string
groups: [ Default, Create, Edit ]
- NotBlank:
groups: [ Edit ]
checkbox:
- Type:
type: boolean
Существует параметр groups, который можно добавить к каждому ограничению. Это массив, содержащий имена групп проверки. При запросе проверки на объект вы можете указать, с каким набором групп вы хотите проверить. Затем система заглянет в файл проверки, какие ограничения следует применять.
По умолчанию группа "По умолчанию" задается для всех ограничений. Это также группа, которая используется при регулярной проверке.
- Вы можете указать группы по умолчанию для определенного типа формы в MyFormType:: getDefaultOptions(), установив параметр validation_groups (массив строк - имена валидации группы),
- При добавлении типа формы в другой, в MyFormType:: buildForm(), вы можете использовать определенные группы проверки.
Это, конечно, стандартное поведение для всех типов форм. Пример:
$formBuilder->add('auto_text', 'textWithAutoValue', array(
'label' => 'my_label',
'validation_groups' => array('Default', 'Edit'),
));
Что касается использования разных объектов, вы можете накапливать свои классы данных по той же архитектуре, что и ваши сложенные формы. В приведенном выше примере тип формы с использованием textWithAutoValueType должен иметь класс данных, который имеет свойство "auto_text" и соответствующий getter/setter.
В файле проверки ограничения Действительные смогут каскадно проверить. Свойство с Действительным определит класс свойства и попытается найти соответствующую конфигурацию проверки для этого класса и применить его с теми же группами проверки:
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
Ответ 2
Как описано здесь https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery#39 (слайд 39) Бернхарда Шуссека (основного участника расширения формы symofny), трансформатор никогда не должен меняться информацию, но только изменить ее представление.
Добавление информации (флажок '= > true), вы делаете что-то неправильно.
В
Edit:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('value', 'text', $options);
$builder->add('checkbox', 'checkbox', array('mapped'=>false));
$builder->addModelTransformer(
new TextWithAutoValueTransformer()
);
}