Passer des options personnalisées à un formulaire symfony2

Dans symfony 1.4, il était possible de paramétrer une définition de classe de formulaire, via les options du formulaire. Est-il possible de passer des options personnalisées à mon type de formulaire personnalisé??? j'ai essayé d'utiliser le paramètre options de la buildForm méthode, mais je ne suis pas très sûr de ce tableau, et apparemment ce n'est pas pour ce que je veux... Merci!

26
demandé sur Throoze 2012-06-06 22:29:47

6 réponses

La solution est simple, si vous voulez que votre option personnalisée soit également disponible dans le modèle Twig, vous devez utiliser $builder->setAttribute() dans buildForm méthode et $view->set() méthode dans buildView() méthode, aussi.

<?php

namespace Acme\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType as FormAbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;

// For Symfony 2.1 and higher:
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

/**
 * ImagePreviewType
 *
 */
class ImagePreviewType extends FormAbstractType
{

    /**
     * {@inheritDoc}
     * For Symfony 2.0
     */
    //public function getDefaultOptions(array $options)
    //{
    //    $options = parent::getDefaultOptions($options);
    //    $options['base_path'] = 'path/to/default/dir/';
    //
    //    return $options;
    //}

    /**
     * {@inheritDoc}
     * For Symfony 2.1 and higher
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'base_path'         => '',
        ));
    }

    /**
     * {@inheritDoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        // For Symfony 2.0:
        // $view->set('base_path', $form->getAttribute('base_path'));

        // For Symfony 2.1 and higher:
        $view->vars['base_path'] = $options['base_path'];
    }

    /**
     * {@inheritDoc}
     */
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->setAttribute('base_path', $options['base_path'])
        ;
    }

    /**
     * {@inheritDoc}
     */
    public function getName()
    {
        return 'image_preview';
    }

    public function getParent(array $options)
    {
        // for Symfony 2.0:
        // return 'field';

        // for Symfony 2.1 and higher:
        return 'form';
    }
}

Modèle pour le type de formulaire personnalisé (fichier ...Acme / DemoBundle / ressources / vues / formulaire / champs.HTML.brindille):

{% block image_preview_widget %}
{% spaceless %}
<img src="{{ base_path ~ value }}" alt=""  {{ block('widget_container_attributes') }} />
{% endspaceless %}
{% endblock %}

Enregistrez votre modèle pour les types de formulaires personnalisés dans app / config / config.yml

twig:
    debug:            %kernel.debug%
    strict_variables: %kernel.debug%
    form:
        resources:
            - 'AcmeDemoAdminBundle:Form:fields.html.twig'

Utilisation: afficher un aperçu de l'image de l'utilisateur lors de l'édition de son profil:

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

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

class UserType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('user_profile_image_file_name', new ImagePreviewType(), array(
            'base_path' => 'some/other/dir',
        ));
    }
}

2014-08-18: Mise à jour pour Symfony 2.1 ou supérieur

41
répondu pulzarraider 2016-12-19 08:58:32

UPDATE: {[14] } Veuillez noter que cette solution ne fonctionne que dans Symfony 2.0.x, qui est obsolète, utilise setDefaultOptions au lieu de getDefaultOptions.


À juste titre, les types de formulaire Symfony 2 acceptent les options que vous pouvez utiliser pour tout ce que vous voulez dans le type de formulaire. Vous devez remplacer la méthode getDefaultOptions pour spécifier vos options de type.

Par exemple, j'ai un type MyCustomType qui acceptent my_option, cette option a une valeur par défaut false, la mise en œuvre de MyCustomType peut être quelque chose comme ce.

class MyCustomType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        if($options['my_option']){
            //do something
        } else {
            //do another thing
        }
        ...
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'my_option' => false
        );
    }

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

Plus Tard, vous aurez besoin de spécifier l'option lorsque vous créez le formulaire dans le contrôleur, en utilisant le troisième paramètre de buildForm:

$form = $this->buildForm(new MyCustomType(), null, array(
    'my_option' => true
));

Si vous ne spécifiez pas l'option my_option, elle prend la valeur par défaut (false).

18
répondu eagleoneraptor 2014-05-11 17:13:24

En utilisant symfony 2.8, j'ai réussi en utilisant la solution proposée en étendant la méthode configureOptions().

class ElementType extends AbstractType
{
    // ...

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'my_custom_option_parameter' => null,
        ));
    }
}

J'avais besoin d'utiliser la ElementType, comme une collection et formulaire intégré. J'ai reconnu qu'il n'était pas possible de passer le my_custom_option_parameter de la CollectionType, parce que je n'ai pas de personnaliser configureOptions() de CollectionType, mais de mon ElementType. Si vous devez passer le my_custom_option_parameter à travers un CollectionType, vous pouvez réussir en définissant my_custom_option_parameter dans entry_options (voir Documentation champ CollectionType) tableau de CollectionType.

Exemple passage de my_custom_option_parameter à travers un CollectionType:

class OuterFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    { 
        //...
        $builder->add('elements', CollectionType::class, array(
            'entry_type' => ElementType::class,
            // ...
            'entry_options' => array(
                'my_custom_option_parameter' => 'value is now set!'
            )
        ));
        //...
    }
}
10
répondu Erik Theoboldt 2016-12-14 14:00:23

J'ai essayé d'utiliser ces options {[1] } sans succès car il semblait qu'il ne pouvait transporter que de petits sous-ensembles prédéfinis de clés. Ce fut, par tous les moyens, inacceptable pour moi...

Cependant, vous pouvez passer toutes les options via la méthode forms __construct et la stocker dans les propriétés de classe pour une utilisation ultérieure. Ensuite, à partir de buildForm vous pouvez y accéder en utilisant $this->"propertyName"...

, C'est à vous de décider si vous voulez passer seul array ou juste quelques variables __construct...

C'est juste une ébauche exemple:

class Foobar{
    private $update = false;

    public function __construct($update = false){
        $this->update = $update;
    }


    public function buildForm(FormBuilder builder, array options){
        if ( $update ){
            // something
        }else{
            // well, this is not an update - do something else
        }
    }
}
2
répondu Jovan Perovic 2012-06-06 21:22:48

En utilisant Symfony 3, j'ai pu passer des options personnalisées au formulaire en définissant une option par défaut dans la méthode OptionsResolver injectée dans configureOptions de ma classe de type de formulaire:

Dans le Contrôleur:

//Compile whatever your options are here. Assume an array is returned
$customOptions = $this->getMyCustomOptions($args);
//Build the form:
$form = $this->createForm(MyCustomFormType::class, array('my_custom_options' => $customOptions));

MyCustomFormType.php:

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => DataModel::class,
        'my_custom_options' => []
    ]);
}
//custom options is now set in "$options" array:
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('my_custom_fields', Type\ChoiceType::class, [
       'choices' => $options['my_custom_options'],
       'mapped' => false //if not part of the data model.
       . . .

Il semble donc que vous puissiez définir un contrat avec votre formulaire et le fournisseur de données pour définir des données arbitraires sur le formulaire.

Je viens d'implémenter avec succès cette procédure. Notez que sur le voyage de retour, puisque vous avez défini 'mapped' => false, dans le formBuilder, $form->getData() ne retourne pas la sélection. Pour obtenir la valeur sélectionnée:

$mySelectedValue = $form->get('my_custom_options')->getViewData();

Dans votre contrôleur. Pourquoi cela est au-delà de moi . . .

2
répondu eggmatters 2016-09-20 21:14:06

En se basant sur la réponse de @ pulzarraider, j'ai créé du code avec des modifications pour Symfony 3.

Vous devez changer

OptionsResolverInterface pour OptionsResolver

FormBuilder pour FormBuilderInterface

Dans mon cas:

namespace MediaBundle\Form;

use Symfony\Component\Form\AbstractType as FormAbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;

class ImageType extends FormAbstractType {

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'max_images' => ''
        ));
    }

    public function buildView(FormView $view, FormInterface $form, array $options) {

        $view->vars['max_images'] = $options['max_images'];
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {

        $builder
                ->setAttribute('max_images', $options['max_images'])
        ;
    }

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

    public function getParent() {
        return TextareaType::class;
    }
}
2
répondu Piotrek Zatorski 2016-12-28 21:55:57