web-dev-qa-db-fra.com

Puis-je mettre du HTML dans un bouton de formulaire Symfony avec Twig?

J'essaie de mettre du HTML dans un bouton de formulaire avec une brindille comme:

{{ form_widget(form.jiraStatus, {
        'label': '<i class="fa fa-bug"></i>Bug',
        'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}

Mais ce faisant, le bouton rendu se présente comme suit:

<button type="submit" name="SolveTask[taskTypesFormObj][bugStatus]"
    class="btn btn-large btn-default btn-block">
    &lt;i class=&quot;fa fa-bug&quot;&gt;&lt;/i&gt;Bug
</button>

Comme vous pouvez le constater, le code HTML contenu dans le bouton est codé. J'ai essayé d'utiliser le filtre brut, mais l'effet est le même. Il y a un moyen de faire ça?

Merci!

24
viscat

Oui, mais vous devrez personnaliser votre thème de formulaire .

Remarque: Cette réponse a été modifiée pour être compatible avec Symfony 2.8 3.x et 4.x. Pour les versions plus anciennes, veuillez consulter l'historique d'édition.

Utiliser des extensions de formulaire est un bon moyen de prendre en charge les icônes dans les boutons. Commencez par créer une classe d'extension de formulaire définissant une nouvelle propriété icône que vous pouvez utiliser dans vos formulaires:

<?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
    }
}

Enregistrez cette extension dans votre fichier services.yml (ou fichier xml). L'alias doit correspondre à la chaîne renvoyée par la méthode getExtendedType() ci-dessus.

# 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 }

Ensuite, remplacez votre form_div_layout.html.twig. (Voir lien ci-dessus) Vous pouvez maintenant utiliser icon comme variable dans ces thèmes. Pour les boutons, nous substituons le bloc 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 %}

Enfin, vous pouvez utiliser l'option icon dans votre modèle:

{{ form_widget(form.jiraStatus, {
    'icon': 'fa-bug',
    'label': 'Bug',
    'attr':{'class': 'btn btn-large btn-default btn-block' }
}) }}

Ou dans vos classes de formulaire:

    $builder
        ->add('jiraStatus', SubmitType::class, [
                'label' => 'Bug',
                'icon' => 'fa-bug',
                'attr' => [
                    'class' => 'btn btn-large btn-default btn-block',
                ],
            ]
        );

Remarque: Il est généralement préférable d’ajouter l’icône dans le modèle car les icônes sont une question de présentation et que vos classes de formulaire doivent vraiment concerner la logique d’affaires.

Le rendre encore plus générique:

En renvoyant le FQCN de ButtonType dans getExtendedType (), nous informons Symfony que nous étendons tous les éléments de formulaire possibles héritant de ButtonType, tels que SubmitType. Malheureusement, aucun type ne peut être utilisé pour cibler tous les éléments de formulaire possibles, mais nous pouvons ajouter une extension supplémentaire qui cible FormType. Tous les champs de formulaire tels que les zones de saisie et les éléments sélectionnés héritent de ce type. Donc, si vous voulez que cela fonctionne avec les deux boutons et des champs de formulaire, je suggère ce qui suit:

Créez une classe abstraite abstract class AbstractIconExtension extends AbstractTypeExtension avec exactement le même contenu que ci-dessus, mais laissez de côté la méthode getExtendedType. Créez ensuite deux classes qui s’étendent à partir de cette classe (par exemple, FieldTypeIconExtension et ButtonTypeIconExtension) qui ne contiennent que la méthode getExtendedType. Un retournant le FQCN de FormType et l'autre renvoyant le FQCN de ButtonType

(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
    }
}

Enregistrez ces deux classes dans vos services en utilisant l'alias correspondant:

# 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 }

Vous pouvez maintenant utiliser la variable icon à d’autres endroits dans vos thèmes de formulaire. Par exemple, pour ajouter des icônes aux étiquettes, vous pouvez remplacer le bloc 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 %} 

Ajoutez ensuite une icône à l'étiquette de ce champ dans votre classe de formulaire:

$builder
    ->add('mytextfield', TextType::class, [
            'label' => 'My fancy text field',
            'icon' => 'fa-thumbs-o-up'
        ]
    );
40
Xatoo

Si vous cherchez une solution plus simple, insérez-la dans votre thème thème :

{%- 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 -%}

Vous pouvez ensuite continuer et insérer du code HTML dans l’étiquette de votre bouton:

{{ form_widget(searchForm.search, {'label': '<span class="glyphicon glyphicon-search" aria-hidden="true"></span>'}) }}
8
Jonathan

voici comment j'ai résolu et testé avec Symfony 4 . Dans le modèle de brindille:

{{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)}}

Dans mon formulaire de contrôleur PHP, je n’ai ajouté aucun bouton, mais seulement des champs de saisie.

   $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();

Ce que j'ai fait pour vérifier la soumission du formulaire, c'est:

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');    
}

J'espère que cela peut aider. Il est bon de dire que même le problème de l'alignement des boutons est résolu car div n'est pas ajouté pour chaque bouton, contrairement à la méthode form add.

1
marfing

Une solution encore plus simple pourrait être de laisser les boutons en dehors du type de formulaire et de définir les attributs name et value. Ensuite, récupérez-les comme vous le feriez avec les paramètres de post normaux dans le contrôleur.

Dans votre modèle:

{{ 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>

Puis dans votre contrôleur

if ($form->isSubmitted() && $form->isValid()) {
    $clicked = $request->request->get('clicked');
}
0
Coder1