Comment faire pour créer un type de formulaire du champ personnalisé


Table des matières

Référence
Définir le type de champ
Création d'un modèle pour le champ
En utilisant le type de champ
Création de votre type de champ en tant que service

Référence

Symfony est livré avec un tas de types de champs de base disponibles pour construire des formes. Cependant, il ya des situations où nous voulons créer un type de formulaire un champ personnalisé dans un but précis. Cette recette suppose que nous besoin d'une définition de champ qui détient le sexe d'une personne, basé sur le champ de choix existant. Cette section explique comment le champ est défini, comment nous pouvons personnaliser sa configuration et enfin, comment nous pouvons l'enregistrer pour une utilisation dans notre application.

Définir le type de champ

Afin de créer le type de champ personnalisé, nous devons d'abord créer la classe qui représente le champ. Dans notre situation de la classe tenant le type de champ sera appelé GenderType et le fichier sera stocké dans l'emplacement par défaut pour les champs de formulaire, qui est <BundleName>\Form\Type. Assurez-vous que le domaine s'étend AbstractType :

# src/Acme/DemoBundle/Form/Type/GenderType.php
namespace Acme\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class GenderType extends AbstractType
{
    public function getDefaultOptions(array $options)
    {
        return array(
            'choices' = > array(
                'm' = > 'Male',
                'f' = > 'Female',
            )
        );
    }

    public function getParent(array $options)
    {
        return 'choice';
    }

    public function getName()
    {
        return 'gender';
    }
}

L'emplacement de ce fichier n'est pas important - Le répertoire Form\Type n'est qu'une convention.

Ici, la valeur de retour de la fonction getParent indique que nous avons décidé d'étendre le type de champ choix. Cela signifie que, par défaut, nous héritons de la logique et du rendu de ce type de champ. Pour voir une partie de la logique, consultez la classe ChoiceType. Il existe trois méthodes qui sont particulièrement importants:

Si vous créez un champ qui se compose de nombreux domaines, alors assurez-vous de définir votre «parent» de type en tant que forme ou de quelque chose qui s'étend formulaire. En outre, si vous avez besoin de modifier la «vue» de l'un de vos types d'enfants à partir de votre type de parent, utilisez le buildViewBottomUp () méthode.

La méthode getName() retourne un identifiant qui doit être unique dans votre application. Il est utilisé dans divers endroits, tels que lors de la personnalisation comment votre type de formulaire sera rendu.

Le but de notre domaine était d'étendre le type de choix pour permettre la sélection d'un des sexes. Ceci est réalisé en fixant les choix d'une liste de genres possibles.

Création d'un modèle pour le champ

Chaque type de champ est rendue par un fragment de modèle, qui est en partie déterminée par la valeur de votre méthode getName(). Pour plus d'informations, voir Comment faire pour personnaliser le rendu de formulaire par thème

Dans ce cas, puisque notre champ parent est un choix, nous n'avons pas besoin de faire un travail que notre type de champ personnalisé sera automatiquement rendu comme un type de choix. Mais pour l'amour de cet exemple, supposons que, lorsque notre champ est "élargi" (c.-à-boutons radio ou des cases à cocher, au lieu d'un champ de sélection), nous voulons toujours rendre dans un élément ul. Dans votre modèle thème formulaire (voir lien ci-dessus pour plus de détails), créez un bloc gender_widget de le gérer:

{# src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}

{% block gender_widget %}
{% spaceless %}
    {% if expanded %}
        <ul {{ block('widget_container_attributes') }}>
        {% for child in form %}
            <li>
                {{ form_widget(child) }}
                {{ form_label(child) }}
            </li>
        {% endfor %}
        </ul>
    {% else %}
        {# just let the choice widget render the select tag #}
        {{ block('choice_widget') }}
    {% endif %}
{% endspaceless %}
{% endblock %}

Assurez-vous que le préfixe widget correct est utilisé. Dans cet exemple, le nom doit être gender_widget, en fonction de la valeur retournée par getName. En outre, le fichier de configuration principal doit pointer vers le modèle de formulaire personnalisé de sorte que il est utilisé lors du rendu de toutes les formes.

# app/config/config.yml

twig:
    form:
        resources:
            - 'AcmeDemoBundle:Form:fields.html.twig'

En utilisant le type de champ

Vous pouvez maintenant utiliser votre type de champ personnalisé immédiatement, simplement en créant une nouvelle instance du type dans un de vos formulaires:

// src/Acme/DemoBundle/Form/Type/AuthorType.php
namespace Acme\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class AuthorType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('gender_code', new GenderType(), array(
            'empty_value' = > 'Choose a gender',
        ));
    }
}

Mais cela ne fonctionne que parce que le GenderType () est très simple. Que faire si les codes de genre ont été stockés dans la configuration ou dans une base de données? La section suivante explique comment les types de champs plus complexes à résoudre ce problème.

Création de votre type de champ en tant que service

Jusqu'à présent, cette entrée a supposé que vous avez un type de champ personnalisé très simple. Mais si vous avez besoin d'accéder à la configuration, une connexion base de données, ou un autre service, alors vous aurez envie d'enregistrer votre type personnalisé comme un service. Par exemple, supposons que nous stockons les paramètres du genre dans la configuration:

Version Yaml

# app/config/config.yml
parameters:
    genders:
        m: Male
        f: Female

Version Xml

<!-- app/config/config.xml -->
<parameters>
    <parameter key="genders" type="collection">
        <parameter key="m">Male</parameter>
        <parameter key="f">Female</parameter>
    </parameter>
</parameters>

Pour utiliser le paramètre, nous allons définir notre type de champ personnalisé comme un service, l'injection de la valeur du paramètre sexes comme premier argument à sa fonction __construct

Version Yaml

# src/Acme/DemoBundle/Resources/config/services.yml
services:
    form.type.gender:
        class: Acme\DemoBundle\Form\Type\GenderType
        arguments:
            - "%genders%"
        tags:
            - { name: form.type, alias: gender }

Version Xml

<!-- src/Acme/DemoBundle/Resources/config/services.xml -->
<service id="form.type.gender" class="Acme\DemoBundle\Form\Type\GenderType">
    <argument>%genders%</argument>
    <tag name="form.type" alias="gender" />
</service>

Assurez-vous que le fichier des services est importé. Voir Importation de configuration avec des importations pour plus de détails.

Assurez-vous que l'alias attribut de la balise correspond à la valeur retournée par la méthode getName défini précédemment. Nous verrons l'importance de ce à un moment où nous utilisons le type de champ personnalisé. Mais d'abord, ajouter un argument à __ construct GenderType, qui reçoit la configuration entre les sexes:

# src/Acme/DemoBundle/Form/Type/GenderType.php
namespace Acme\DemoBundle\Form\Type;
// ...

class GenderType extends AbstractType
{
    private $genderChoices;

    public function __construct(array $genderChoices)
    {
        $this->genderChoices = $genderChoices;
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'choices' = > $this->genderChoices,
        );
    }

    // ...
}

Ca y est! Le GenderType est maintenant alimentée par les paramètres de configuration et enregistré comme un service. Et parce que nous avons utilisé les alias form.type dans sa configuration, en utilisant le champ est maintenant beaucoup plus facile:

// src/Acme/DemoBundle/Form/Type/AuthorType.php
namespace Acme\DemoBundle\Form\Type;
// ...

class AuthorType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('gender_code', 'gender', array(
            'empty_value' = > 'Choose a gender',
        ));
    }
}

Notez qu'à la place de l'instanciation d'une nouvelle instance, nous ne pouvons tout simplement se référer à elle par les alias utilisés dans la configuration de notre service.