Symfony: Как избежать того, чтобы пользовательские типы форм автоматически помещались в div?
Форма пользовательского типа:
class UserType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email', 'email', ['label' => 'EMail']);
// various other fields....
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('registration'),
'data_class' => 'Vendor\Model\Entity\User',
));
}
public function getName()
{
return 'form_user';
}
}
Форма TutorType:
class TutorType extends Translate
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType(), ['label' => false]);
$builder->add('school', 'entity', [
'class' => 'Model:School',
'property' => 'name',
'label' => 'Label'
]);
// Various other fields
$builder->add('save', 'Submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
//'validation_groups' => array('registration'),
'data_class' => 'Vendor\Model\Entity\Tutor',
'cascade_validation' => true,
));
}
public function getName()
{
return 'form_tutor';
}
}
При рендеринге UserType
отображается внутри div, я не могу найти способ преодолеть это.
Форма представляется как
<form name="form_tutor"
method="post"
action=""
novalidate="novalidate"
class="form-horizontal form-horizontal"
id="form_tutor">
<div id="form_tutor"
novalidate="novalidate"
class="form-horizontal">
<div class="form-group">
<div class="col-lg-10">
<div id="form_tutor_user">
<div class="form-group">
<label class="col-lg-2 control-label aaaa required"
for="form_tutor_user_email">EMail</label>
<div class="col-lg-10">
<input type="email"
id="form_tutor_user_email"
name="form_tutor[user][email]"
required="required"
class="form-control" />
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label aaaa required"
for="form_tutor_tutorType">Type</label>
<div class="col-lg-10">
<select id="form_tutor_tutorType"
name="form_tutor[tutorType]"
class="form-control">
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit"
id="form_tutor_save"
name="form_tutor[save]"
class="btn btn-default">Speichern</button>
</div>
</div><input type="hidden"
id="form_tutor__token"
name="form_tutor[_token]"
class="form-control"
value="s6i6zPxJs7KU5CiEe8i6Ahg_ca8rc2t5CnSk5yAsUhk" />
</div>
</form>
form_tutor_user
оборачивается в собственный div группы форм. Я пытался перезаписать form_tutor_user_widget, но это один уровень до глубины. (И только быстрое исправление, оно должно применяться глобально ко всем типам форм - Классы)
Как я могу изменить тему, чтобы не все пользовательские типы не оборачивались шаблоном form_row по умолчанию?
Или как я узнаю в ветке, когда отображается "subform"? так что я могу решить напечатать <div class="form-group">
когда дочерний узел не является подчиненной формой, или пропустите ее, если это так.
ТИА
5 ответов
По умолчанию в базовой форме темы:
{% block form_row %}
{% spaceless %}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
И, для пользовательских составных форм:
{% block form_widget_compound %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% if form.parent is empty %}
{{ form_errors(form) }}
{% endif %}
{{ block('form_rows') }}
{{ form_rest(form) }}
</div>
{% endspaceless %}
{% endblock form_widget_compound %}
Если вы не изменили что-то здесь, DIV, который вы видите, должен исходить из одного или другого фрагмента шаблона.
Однако, в вашем конкретном примере, если определен form_tutor_user_row, первый бит никогда не используется, а если определен form_tutor_user_widget, последний бит никогда не используется.
Вернемся к вашему вопросу. Ваш вопрос: "Как я могу изменить тему, чтобы не все пользовательские типы не оборачивались шаблоном form_row по умолчанию?"
Вот проблема, с которой я ее вижу: вы хотите, чтобы все ваши ТОП-формы (формы, в которые включены все подформы) имели общий способ рендеринга в разделах. Каждый раздел будет включен в DIV с class="form-group". Вы можете добавить некоторые дополнительные операции рендеринга, но я ограничусь этим, чтобы все было просто.
Затем вам нужно создать специальный тип формы и сделать так, чтобы все ваши ТОП-формы наследовали от этого нового типа формы. Например:
class TopType extends AbstractType
{
public function getName()
{
return 'top_form';
}
}
... и унаследованная форма:
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
}
public function getName()
{
return 'my_form';
}
public function getParent()
{
return 'top_form';
}
}
Как видите, для работы наследования форм нет необходимости создавать PHP-наследование.
Применительно к шаблонам (могу ли я даже сказать это?), Если для my_form не задана конкретная тема, Symfony поймет, что используемая здесь тема формы по умолчанию - это тема формы top_form, которую вы можете определить так:
{% block top_form_widget %}
{% spaceless %}
{% for child in form %}
<div class="form-group">
{{ form_widget(child) }}
</div>
{% endfor %}
{{ form_rest(form) }}
{% endspaceless %}
{% endblock top_form_widget %}
Я должен добавить, что это проблема, с которой я уже столкнулся и решил. Скажи мне, как это работает для тебя.
Редактировать:
Подводя итог, вы должны сделать следующее:
- Создайте тип формы TopType,
- Добавьте блок top_form_widget в тему формы,
- Для всех ваших корневых форм (то есть форм верхнего уровня, форм, у которых нет родителя), добавьте метод getParent(), который будет возвращать имя вашей формы TopType ("top_form")
Теоретически, если вы переопределите form_widget_compound
таким образом заблокируйте в глобальной теме форму, она должна работать так, как вы хотите:
// app/Resources/views/form.html.twig
{% block form_widget_compound %}
{% if form.parent is empty %}
<div {{ block('widget_container_attributes') }}>
{{ form_errors(form) }}
{% endif %}
{{ block('form_rows') }}
{{ form_rest(form) }}
{% if form.parent is empty %}
</div>
{% endif %}
{% endblock %}
И зарегистрируйте свою форму темы:
// app/config/config.yml
twig:
form:
resources:
- "::form.html.twig"
Я обычно решаю эту проблему путем рендеринга полей вложенной формы вручную:
{{ form_row(form.tutor.school) }}
{{ form_row(form.tutor.user.email) }}
Возможно, это не самое элегантное решение, но оно работает для меня, и я еще не искал элегантного.
Bootstrap 3.3.4 В итоге я этим и занимался.
Они ключевая часть этого:
<div class="{% if form.parent.parent is empty %}form-group{% endif %}{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
Полный шаблон.
{% block form_row -%}
<div class="{% if form.parent.parent is empty %}form-group{% endif %}{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
{% if form.parent.parent is null and label is not empty %}
{{- form_label(form) -}}
{% elseif label is empty %}
{{- form_label(form) -}}
{% endif %}
{% if compound is empty %}<div class="{{ block('form_group_class') }}">{% endif %}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
{% if compound is empty %}</div>{% endif %}
</div>
{%- endblock form_row %}
Возможно, это не изящное решение, но оно работает для меня, потому что я тоже пытался найти решение.
В качестве примера:
{% for custom_field in form.custom_fields %}
<div class="edit_custom">
{{ form_row(custom_field.name) }}
{{ form_row(custom_field.value) }}
</div>
{% endfor %}
<script>
$('.edit_custom').find('input').unwrap();
</script>
Попробуйте использовать form_themes.
Во-первых, в родительском шаблоне определите тему формы:
{% form_theme form with ['BundleName:ControlerName:somesubform_form.html.twig'] %}
Кстати, замените BundleName, ControllerName и somesubform собственными именами.
тогда сделайте это с помощью:
{{ form_row(form.somesubform) }}