#symfony #twig #symfony-forms
#symfony #ветка #symfony-forms
Вопрос:
Я хочу переопределить, как отображаются части моей формы, но я всегда забываю, какие имена блоков ветки отображаются symfony forms. Если блок не найден, я не получаю обратной связи, почему not не был найден и как он должен был быть вызван.
Пример:
class SetPasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('plainPassword', PasswordType::class);
$builder->add('repeatPlainPassword', PasswordType::class);
}
}
Три основных вопроса:
- Как symfony forms определяет имена блоков ветки для
SetPasswordType
? - Как я могу это посмотреть?
- Как я могу это настроить?
Ответ №1:
Для этого конкретного типа widget
имя блока ветки set_password_widget
равно .
Переопределите его в вашей теме формы следующим образом:
{% block set_password_widget %}
<div class="row">
<div class="col">
{{ form_row(form.plainPassword) }}
</div>
<div class="col">
{{ form_row(form.repeatPlainPassword) }}
</div>
</div>
{% endblock %}
Как переопределить блок
- Определите префикс блока, который по умолчанию зависит от имени класса. Для
SetPasswordType
этогоset_password
- Решите, какой блок вы хотите отобразить. Если вы хотите изменить макет, скорее всего, вы переопределите
row
блок. Если вы хотите изменить ввод, скорее всего, вы переопределитеwidget
блок. Обратитесь к документации: https://symfony.com/doc/current/form/form_themes.html#form-fragment-naming - Соедините префикс блока и имя блока вместе. Для
widget
блокаSetPasswordType
, который вы хотите переопределитьset_password_widget
. - Поместите веточный блок в тему формы.
Устранение неполадок в случае сбоя переопределения
- Убедитесь, что блок ветки находится в файле, настроенном в
twig.form_themes
или иным образом, как включенная тема формы. - Проверьте
$blockPrefixes
,SymfonyComponentFormExtensionCoreTypeBaseType::buildView
какие префиксы блоков были определены. Сначала будет ищется последняя запись в массиве. - Проверьте
$blockNameHierarchy
,SymfonyComponentFormFormRenderer::searchAndRenderBlock
какие конкретные блоки ищутся. Сначала будет ищется последняя запись в массиве.
Подробное пошаговое руководство
Имена блоков накапливаются внутри SymfonyComponentFormExtensionCoreTypeBaseType::buildView
$blockPrefixes
переменной. $blockPrefixes
определяет следующий приоритет (первое упоминание = наивысший приоритет. Оно сохраняется в обратном порядке!):
- уникальное имя блока (построенное иерархически на основе имен свойств).
- префикс блока, если он настроен
- имя типа (если наследуется от
AbstractType
, имя генерируется вAbstractType::getBlockPrefix()
) - имя всех родительских типов (следуя цепочке
FormTypeInterface::getParent()
метода).
Например, это может выглядеть так:
$blockPrefixes = [
0 => "form", # because `AbstractType::getParent()` returns `FormType`
1 => "set_password", # our type, name resolved automatically depending on class name
## at this position, a block prefix would be included if one is configured
2 => "_set_password" # the hierarchical unique name, prefixed with `_`. for the plainPassword field, this value would be "searchAndRenderBlock".
];
Когда форма отображается с помощью twig, SymfonyComponentFormFormRenderer::searchAndRenderBlock
вызывается с соответствующим $blockNameSuffix
(например widget
, или row
). Создается $blockNameHierarchy
путем суффикса каждого потенциального префикса с $blockNameSuffix
помощью .
Потому $blockNameSuffix == "row"
что тогда это выглядело бы так:
$blockNameHierarchy = [
0 => "form_widget",
1 => "set_password_widget",
2 => "_set_password_widget"];
Эти блоки ищутся, и выбирается тот, который имеет наивысший приоритет, который может быть найден. Чем позже в массиве, тем выше приоритет.
Настройка префиксов блоков
Вы можете настроить префиксы следующим образом:
class SetPasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('plainPassword', PasswordType::class, ['mapped' => false]);
$builder->add('repeatPlainPassword', PasswordType::class, ['mapped' => false]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('block_prefix', 'my_custom_prefix');
$resolver->setDefault('block_name', 'my_custom_name');
}
}
Это приведет к
$blockPrefixes = [
0 => "form",
1 => "set_password", # this will stay the same as its resolved depending on type name
2 => "my_custom_prefix", # as per our configuration, we now have a custom prefix
3 => "_my_custom_name" # the custom name will be used to determine the hierarchical name
];