2012-06-06 9 views
23

in symfony 1.4 è stato possibile parametrizzare una definizione di classe modulo, tramite le opzioni del modulo. C'è un modo per passare opzioni personalizzate al mio tipo di modulo personalizzato ??? Ho provato ad usare il parametro options del metodo buildForm, ma non sono molto sicuro di cosa sia questa matrice, e apparentemente non è per quello che voglio ... Grazie!Passa le opzioni personalizzate a un modulo symfony2

risposta

39

la soluzione è semplice, se volete che il vostro opzione personalizzata sia disponibile anche nel modello di Twig, è necessario utilizzare $builder->setAttribute() in buildForm metodo e $view->set() metodo buildView() metodo, anche.

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

Template per il tipo di modulo personalizzato (file ... Acme/DemoBundle/Resources/views/Form/fields.html.twig):

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

Registrare il modello per i tipi di modulo personalizzato in App/config/config.yml

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

Usage: mostrare un'anteprima dell'immagine dell'utente mentre si modifica il suo profilo:

// 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: Aggiornamento per Symfony 2.1 o superiore

+0

Mi mancava il passaggio con buildView per passare l'opzione a Twig! grazie! – ROLO

+0

E se volessi aggiungere un'opzione a TUTTI i tipi di modulo (compresi quelli di default)? C'è un modo semplice per farlo? – smarques

+0

È possibile con [Form Type Extension] (http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html). – pulzarraider

2

Ho provato a utilizzare le opzioni array senza esito poiché sembrava che potesse contenere solo un piccolo sottoinsieme predefinito di chiavi. Questo era, per tutti i mezzi, inaccettabile per me ...

Tuttavia, è possibile passare tutte le opzioni tramite il metodo __construct e memorizzarlo nelle proprietà della classe per un utilizzo successivo. Poi, da buildForm è possibile accedervi utilizzando $this->"propertyName" ...

Sta a voi decidere se si desidera passare singolo array o solo poche variabili per __construct ...

Questo è solo un esempio di massima:

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

UPDATE: si prega di notare che questa soluzione funziona solo in Symfony 2.0.x, che è obsoleto, utilizzare setDefaultOptions invece di getDefaultOptions.


Giustamente, i tipi di modulo Symfony 2 accettano opzioni che è possibile utilizzare per qualsiasi cosa si desideri all'interno del tipo di modulo. È necessario sostituire il metodo getDefaultOptions per specificare le opzioni del tipo.

Ad esempio, ho un tipo MyCustomType che accettano my_option, questa opzione ha un valore predefinito di false, l'attuazione di MyCustomType può essere qualcosa di simile.

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

In seguito, è necessario specificare l'opzione quando si crea il modulo nel controller, utilizzando il terzo parametro di buildForm:

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

Se non si specifica l'opzione my_option, prende il valore predefinito (false).

+0

Ho provato questo prima di chiedere qui ... ma, come dice @jperovic, supporta solo un piccolo insieme di chiavi predefinite nella gamma di opzioni ... Non ho ancora provato la sua soluzione ... ma lo farò it ... grazie comunque! – Throoze

+4

Questa soluzione supporta qualsiasi chiave che si desidera utilizzare, basta sovrascrivere il metodo 'getDefaultOptions'. – eagleoneraptor

+0

Forse questa risposta non è adatta all'autore della domanda, ma sicuramente mi è stata utile. Per questo motivo, +1. :) – Sasa

9

Utilizzando symfony 2.8, I riuscito utilizzando la soluzione proposta estendendo il metodo configureOptions().

class ElementType extends AbstractType 
{ 
    // ... 

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

avevo bisogno di usare il ElementType, come una collezione e la forma embedded. Ho riconosciuto che non è stato possibile passare loallo CollectionType, perché non ho personalizzatodi CollectionType, ma del mio ElementType. Se è necessario passare my_custom_option_parameter tramite CollectionType, è possibile riuscire a definire my_custom_option_parameter nella serie entry_options (vedere la documentazione CollectionType Field) di CollectionType.

Esempio passando my_custom_option_parameter attraverso 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!' 
      ) 
     )); 
     //... 
    } 
} 
1

Utilizzando Symfony 3, sono stato in grado di passare le opzioni personalizzate per la forma impostando un'opzione predefinita nel OptionsResolver iniettato in modo configureOptions della mia classe tipo di modulo:

Nel controller:

//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:

Quindi, sembra che sia possibile definire un contratto con il modulo e il fornitore di dati per impostare dati arbitrari sul modulo.

Ho appena implementato questa procedura con successo. Tieni presente che durante il viaggio di ritorno, dal momento che hai impostato 'mapped' => false, nel formBuilder, $form->getData() non restituirà la selezione. Per ottenere il valore selezionato:

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

nel controller. Perché questo è oltre me. . .

2

basandosi su @pulzarraider risposta che ho creato il codice con i cambiamenti di Symfony 3.

È necessario modificare

OptionsResolverInterface per OptionsResolver

FormBuilder per FormBuilderInterface

Nel mio caso:

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; 
    } 
} 
Problemi correlati