Узнать / настроить имя веточного блока Symfony Forms

#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
];