我可以使用 Twig 将 html 放入 Symfony 表单按钮中吗?
Can I put html inside a Symfony form button with Twig?
我正在尝试将 html 放入带有树枝的表单按钮中,例如:
{{ form_widget(form.jiraStatus, {
'label': '<i class="fa fa-bug"></i>Bug',
'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}
但是这样做,渲染按钮显示如下:
<button type="submit" name="SolveTask[taskTypesFormObj][bugStatus]"
class="btn btn-large btn-default btn-block">
<i class="fa fa-bug"></i>Bug
</button>
如您所见,按钮内部的 html 已编码。我尝试使用原始过滤器,但效果是一样的。有办法吗?
谢谢!
是的,但您必须自定义 your form theme。
Note: This answer has been edited to be compatible with Symfony 2.8 3.x and 4.x. For older versions, please see the edit history.
在按钮中支持图标的一个好方法是使用表单扩展。首先创建一个表单扩展 class,它定义了一个新的 属性 图标 ,您可以在表单中使用它:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ButtonTypeIconExtension extends AbstractTypeExtension
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('icon', $options['icon']);
}
/**
* @param FormView $view
* @param FormInterface $form
* @param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['icon'] = $options['icon'];
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['icon' => null]);
$resolver->setDefined(['icon']);
}
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return ButtonType::class; // Extend the button field type
}
}
在您的 services.yml(或 xml 文件)中注册此扩展。别名必须与上述 getExtendedType()
方法返回的字符串相对应。
# Form extension for adding icons
foobar.form_extension.icon:
class: Foo\BarBundle\Form\Extension\ButtonTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\ButtonType }
接下来,覆盖您的 form_div_layout.html.twig
。 (参见上面的 link)您现在可以在这些主题中使用 icon
作为变量。对于按钮,我们覆盖 button_widget
块:
{% block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' btn')|trim}) %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
{% if icon|default %}
{% set iconHtml = '<i class="fa ' ~ icon ~ '"></i> ' %}
{% else %}
{% set iconHtml = '' %}
{% endif %}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ iconHtml|raw }}{{ label|trans({}, translation_domain) }}</button>
{%- endblock button_widget %}
最后,您可以在模板中使用图标选项:
{{ form_widget(form.jiraStatus, {
'icon': 'fa-bug',
'label': 'Bug',
'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}
或者在你的表格中 classes:
$builder
->add('jiraStatus', SubmitType::class, [
'label' => 'Bug',
'icon' => 'fa-bug',
'attr' => [
'class' => 'btn btn-large btn-default btn-block',
],
]
);
注意:通常最好在模板中添加图标,因为图标只是表示形式,您的表单 classes 应该真正与业务逻辑有关。
让它更通用:
通过在 getExtendedType() 中返回 ButtonType 的 FQCN,我们告诉 Symfony 我们正在扩展所有可能继承自 ButtonType 的表单元素,例如 SubmitType。不幸的是,没有一种类型可以用来定位所有可能的表单元素,但我们可以添加一个额外的扩展来定位 FormType。输入框和 select 元素等所有表单字段都继承自此类型。因此,如果您希望它与表单字段 和 按钮一起使用,我建议如下:
创建一个摘要 class abstract class AbstractIconExtension extends AbstractTypeExtension
,内容与上面完全相同,但省略了 getExtendedType
方法。然后创建两个从 class 扩展的 classes(例如 FieldTypeIconExtension
和 ButtonTypeIconExtension
),它们只包含 getExtendedType
方法。一个返回 FormType
的 FQCN,另一个返回 ButtonType
的 FQCN:
Foo/BarBundle/Form/Extension/ButtonTypeIconExtension.php:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
class ButtonTypeIconExtension extends AbstractIconExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return ButtonType::class; // extend all buttons
}
}
Foo/BarBundle/Form/Extension/FieldTypeIconExtension.php:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
class FieldTypeIconExtension extends AbstractIconExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return FormType::class; // extend all field types
}
}
使用相应的别名在您的服务中注册这两个 class:
# Form extensions for adding icons to form elements
foobar.form_extension.button_icon:
class: Foo\BarBundle\Form\Extension\ButtonTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\ButtonType }
foobar.form_extension.form_icon:
class: Foo\BarBundle\Form\Extension\FieldTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }
现在您也可以在表单主题的其他地方使用 icon
变量。例如,要将图标添加到标签,您可以覆盖 form_label
块:
{% block form_label -%}
{% if label is not sameas(false) -%}
{% if not compound -%}
{% set label_attr = label_attr|merge({'for': id}) %}
{%- endif %}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
{% if icon|default %}
{% set iconHtml = '<i class="fa ' ~ icon ~ '"></i> ' %}
{% else %}
{% set iconHtml = '' %}
{% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ iconHtml|raw }}{{ label|trans({}, translation_domain) }}</label>
{%- endif %}
{%- endblock form_label %}
然后在您的表单中为该字段的标签添加一个图标 class:
$builder
->add('mytextfield', TextType::class, [
'label' => 'My fancy text field',
'icon' => 'fa-thumbs-o-up'
]
);
如果您正在寻找更简单的解决方案,只需将其插入您的 form theme:
{%- block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default('btn-default') ~ ' btn')|trim}) %}
{%- if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain)|raw }}</button>
{%- endblock button_widget -%}
然后您可以继续在按钮标签中插入 HTML:
{{ form_widget(searchForm.search, {'label': '<span class="glyphicon glyphicon-search" aria-hidden="true"></span>'}) }}
一个更简单的解决方案可能是将按钮从表单类型中移除并设置 name
和 value
属性。然后像在控制器中正常 post 参数一样检索它们。
在您的模板中:
{{ form_start(form) }}
<button name="clicked" value="saveDraft" class="btn btn-warning">
<i class="fa fa-square-o"></i> Save as Draft
</button>
<button name="clicked" value="saveComplete" class="btn btn-warning">
<i class="fa fa-check-square-o"></i> Save as Complete
</button>
然后在你的控制器中
if ($form->isSubmitted() && $form->isValid()) {
$clicked = $request->request->get('clicked');
}
这就是我用 Symfony 4 解决和测试的方法。
在树枝模板中:
{{form_start(form)}}
{{form_widget(form)}}
<div class="class row">
<div class="class col-sm-offset col-sm-10">
<button name='create' type='submit' value='create' class='btn btn-primary'>Save</button>
<button name='cancel' type='submit' value='cancel' class='btn btn-cancel' formnovalidate='formnovalidate'>Cancel</button>
</div>
</div>
{{form_end(form)}}
在我的 PHP 控制器表单中,我没有添加任何按钮,只是输入字段。
$form = $this->createFormBuilder($article)
->add('title',TextType::class, array(
'data' => $article->getTitle(),
'attr' => array('class' => 'form-control')))
->add('body', TextareaType::class, array(
'data' => $article->getBody(),
'required' => false,
'attr' => array('class' => 'form-control')))
->getForm();
我检查表单提交时所做的是:
if($form->isSubmitted() ){
if($request->request->get('create') && $form->isValid()){
$article = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($article);
$entityManager->flush();
} //l'alternativa può solo essere il cancel
return $this->redirectToRoute('article_list');
}
希望这对您有所帮助。很高兴地说,即使按钮对齐的问题也解决了,因为 div
并没有像表单 add
方法那样为每个按钮添加。
在 Symfony 5.1 上,您可以像这样将 html 内容添加到按钮标签中:
{{ form_widget(form.submit, { 'label': '<i class="fas fa-calculator"></i> Calculate prices', 'label_html' : true })}}
您需要传递选项 "label_html" : true
您可以从 form_div_layout.html.twig 文件中查看原始 Symfony/Twig 代码以了解它:
{%- block button_widget -%}
{%- if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- elseif label is not same as(false) -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>
{%- if translation_domain is same as(false) -%}
{%- if label_html is same as(false) -%}
{{- label -}}
{%- else -%}
{{- label|raw -}}
{%- endif -%}
{%- else -%}
{%- if label_html is same as(false) -%}
{{- label|trans(label_translation_parameters, translation_domain) -}}
{%- else -%}
{{- label|trans(label_translation_parameters, translation_domain)|raw -}}
{%- endif -%}
{%- endif -%}
</button>
{%- endblock button_widget -%}
我正在尝试将 html 放入带有树枝的表单按钮中,例如:
{{ form_widget(form.jiraStatus, {
'label': '<i class="fa fa-bug"></i>Bug',
'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}
但是这样做,渲染按钮显示如下:
<button type="submit" name="SolveTask[taskTypesFormObj][bugStatus]"
class="btn btn-large btn-default btn-block">
<i class="fa fa-bug"></i>Bug
</button>
如您所见,按钮内部的 html 已编码。我尝试使用原始过滤器,但效果是一样的。有办法吗?
谢谢!
是的,但您必须自定义 your form theme。
Note: This answer has been edited to be compatible with Symfony 2.8 3.x and 4.x. For older versions, please see the edit history.
在按钮中支持图标的一个好方法是使用表单扩展。首先创建一个表单扩展 class,它定义了一个新的 属性 图标 ,您可以在表单中使用它:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ButtonTypeIconExtension extends AbstractTypeExtension
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('icon', $options['icon']);
}
/**
* @param FormView $view
* @param FormInterface $form
* @param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['icon'] = $options['icon'];
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['icon' => null]);
$resolver->setDefined(['icon']);
}
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return ButtonType::class; // Extend the button field type
}
}
在您的 services.yml(或 xml 文件)中注册此扩展。别名必须与上述 getExtendedType()
方法返回的字符串相对应。
# Form extension for adding icons
foobar.form_extension.icon:
class: Foo\BarBundle\Form\Extension\ButtonTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\ButtonType }
接下来,覆盖您的 form_div_layout.html.twig
。 (参见上面的 link)您现在可以在这些主题中使用 icon
作为变量。对于按钮,我们覆盖 button_widget
块:
{% block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' btn')|trim}) %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
{% if icon|default %}
{% set iconHtml = '<i class="fa ' ~ icon ~ '"></i> ' %}
{% else %}
{% set iconHtml = '' %}
{% endif %}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ iconHtml|raw }}{{ label|trans({}, translation_domain) }}</button>
{%- endblock button_widget %}
最后,您可以在模板中使用图标选项:
{{ form_widget(form.jiraStatus, {
'icon': 'fa-bug',
'label': 'Bug',
'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}
或者在你的表格中 classes:
$builder
->add('jiraStatus', SubmitType::class, [
'label' => 'Bug',
'icon' => 'fa-bug',
'attr' => [
'class' => 'btn btn-large btn-default btn-block',
],
]
);
注意:通常最好在模板中添加图标,因为图标只是表示形式,您的表单 classes 应该真正与业务逻辑有关。
让它更通用:
通过在 getExtendedType() 中返回 ButtonType 的 FQCN,我们告诉 Symfony 我们正在扩展所有可能继承自 ButtonType 的表单元素,例如 SubmitType。不幸的是,没有一种类型可以用来定位所有可能的表单元素,但我们可以添加一个额外的扩展来定位 FormType。输入框和 select 元素等所有表单字段都继承自此类型。因此,如果您希望它与表单字段 和 按钮一起使用,我建议如下:
创建一个摘要 class abstract class AbstractIconExtension extends AbstractTypeExtension
,内容与上面完全相同,但省略了 getExtendedType
方法。然后创建两个从 class 扩展的 classes(例如 FieldTypeIconExtension
和 ButtonTypeIconExtension
),它们只包含 getExtendedType
方法。一个返回 FormType
的 FQCN,另一个返回 ButtonType
的 FQCN:
Foo/BarBundle/Form/Extension/ButtonTypeIconExtension.php:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
class ButtonTypeIconExtension extends AbstractIconExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return ButtonType::class; // extend all buttons
}
}
Foo/BarBundle/Form/Extension/FieldTypeIconExtension.php:
<?php
namespace Foo\BarBundle\Form\Extension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
class FieldTypeIconExtension extends AbstractIconExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return FormType::class; // extend all field types
}
}
使用相应的别名在您的服务中注册这两个 class:
# Form extensions for adding icons to form elements
foobar.form_extension.button_icon:
class: Foo\BarBundle\Form\Extension\ButtonTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\ButtonType }
foobar.form_extension.form_icon:
class: Foo\BarBundle\Form\Extension\FieldTypeIconExtension
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }
现在您也可以在表单主题的其他地方使用 icon
变量。例如,要将图标添加到标签,您可以覆盖 form_label
块:
{% block form_label -%}
{% if label is not sameas(false) -%}
{% if not compound -%}
{% set label_attr = label_attr|merge({'for': id}) %}
{%- endif %}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
{% if icon|default %}
{% set iconHtml = '<i class="fa ' ~ icon ~ '"></i> ' %}
{% else %}
{% set iconHtml = '' %}
{% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ iconHtml|raw }}{{ label|trans({}, translation_domain) }}</label>
{%- endif %}
{%- endblock form_label %}
然后在您的表单中为该字段的标签添加一个图标 class:
$builder
->add('mytextfield', TextType::class, [
'label' => 'My fancy text field',
'icon' => 'fa-thumbs-o-up'
]
);
如果您正在寻找更简单的解决方案,只需将其插入您的 form theme:
{%- block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default('btn-default') ~ ' btn')|trim}) %}
{%- if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain)|raw }}</button>
{%- endblock button_widget -%}
然后您可以继续在按钮标签中插入 HTML:
{{ form_widget(searchForm.search, {'label': '<span class="glyphicon glyphicon-search" aria-hidden="true"></span>'}) }}
一个更简单的解决方案可能是将按钮从表单类型中移除并设置 name
和 value
属性。然后像在控制器中正常 post 参数一样检索它们。
在您的模板中:
{{ form_start(form) }}
<button name="clicked" value="saveDraft" class="btn btn-warning">
<i class="fa fa-square-o"></i> Save as Draft
</button>
<button name="clicked" value="saveComplete" class="btn btn-warning">
<i class="fa fa-check-square-o"></i> Save as Complete
</button>
然后在你的控制器中
if ($form->isSubmitted() && $form->isValid()) {
$clicked = $request->request->get('clicked');
}
这就是我用 Symfony 4 解决和测试的方法。 在树枝模板中:
{{form_start(form)}}
{{form_widget(form)}}
<div class="class row">
<div class="class col-sm-offset col-sm-10">
<button name='create' type='submit' value='create' class='btn btn-primary'>Save</button>
<button name='cancel' type='submit' value='cancel' class='btn btn-cancel' formnovalidate='formnovalidate'>Cancel</button>
</div>
</div>
{{form_end(form)}}
在我的 PHP 控制器表单中,我没有添加任何按钮,只是输入字段。
$form = $this->createFormBuilder($article)
->add('title',TextType::class, array(
'data' => $article->getTitle(),
'attr' => array('class' => 'form-control')))
->add('body', TextareaType::class, array(
'data' => $article->getBody(),
'required' => false,
'attr' => array('class' => 'form-control')))
->getForm();
我检查表单提交时所做的是:
if($form->isSubmitted() ){
if($request->request->get('create') && $form->isValid()){
$article = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($article);
$entityManager->flush();
} //l'alternativa può solo essere il cancel
return $this->redirectToRoute('article_list');
}
希望这对您有所帮助。很高兴地说,即使按钮对齐的问题也解决了,因为 div
并没有像表单 add
方法那样为每个按钮添加。
在 Symfony 5.1 上,您可以像这样将 html 内容添加到按钮标签中:
{{ form_widget(form.submit, { 'label': '<i class="fas fa-calculator"></i> Calculate prices', 'label_html' : true })}}
您需要传递选项 "label_html" : true
您可以从 form_div_layout.html.twig 文件中查看原始 Symfony/Twig 代码以了解它:
{%- block button_widget -%}
{%- if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- elseif label is not same as(false) -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>
{%- if translation_domain is same as(false) -%}
{%- if label_html is same as(false) -%}
{{- label -}}
{%- else -%}
{{- label|raw -}}
{%- endif -%}
{%- else -%}
{%- if label_html is same as(false) -%}
{{- label|trans(label_translation_parameters, translation_domain) -}}
{%- else -%}
{{- label|trans(label_translation_parameters, translation_domain)|raw -}}
{%- endif -%}
{%- endif -%}
</button>
{%- endblock button_widget -%}