2012-06-06 21 views
23

en symfony 1.4. Se puede parametrizar una definición de clase de formulario, a través de las opciones del formulario. ¿Hay alguna forma de pasar opciones personalizadas a mi tipo de formulario personalizado ??? He intentado usar el parámetro de opciones del método buildForm, pero no estoy muy seguro de qué es esta matriz, y aparentemente no es lo que quiero ... ¡Gracias!Pase opciones personalizadas a un formulario symfony2

Respuesta

39

La solución es simple, si usted quiere que su opción personalizada esté disponible también en la plantilla de la ramita, debe utilizar $builder->setAttribute() en buildForm método y $view->set() método en el buildView() método, también.

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

plantilla para el tipo de formulario personalizado (archivo ... 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 %} 

Registre su plantilla para este tipo de formulario personalizado en aplicación/config/config.yml

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

Uso: Pantalla de vista previa de la imagen del usuario durante la edición de su perfil:

// 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: Actualización para Symfony 2.1 o superior

+0

me faltaba el paso con buildView para la opción de pasar a Twig! ¡gracias! – ROLO

+0

¿Qué sucede si quiero agregar una opción a TODOS los tipos de formularios (incluidos los predeterminados)? ¿Hay una manera fácil de hacer eso? – smarques

+0

Es posible con [Extensión de tipo de formulario] (http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html). – pulzarraider

2

He intentado utilizar las opciones array sin éxito ya que parecía que solo podía llevar un pequeño subconjunto predefinido de claves. Esto fue, por supuesto, inaceptable para mí ...

Sin embargo, puede pasar todas las opciones a través del formulario __construct y almacenarlo en las propiedades de la clase para su uso posterior. Luego, a partir buildForm se puede acceder a él mediante $this->"propertyName" ...

Depende de usted decidir si desea pasar un solo array o sólo unas pocas variables a __construct ...

Esto es sólo un ejemplo aproximado:

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

ACTUALIZACIÓN: Tenga en cuenta que esta solución sólo funciona en Symfony 2.0.x, que es obsoleta, utilice setDefaultOptions en lugar de getDefaultOptions.


Justamente, tipos de Symfony 2 forman aceptan opciones que se pueden utilizar para cualquier cosa que desee dentro del tipo de formulario. Debe sobrescribir el método getDefaultOptions para especificar sus opciones de tipo.

Por ejemplo, tengo un tipo MyCustomType que aceptan my_option, esta opción tiene un valor predeterminado de false, la implementación de MyCustomType puede ser algo como esto.

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

Más tarde, tendrá que especificar la opción al crear el formulario en el controlador, usando el tercer parámetro de buildForm:

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

Si no especifica la opción my_option, toma la valor predeterminado (false).

+0

Intenté esto antes de preguntar aquí ... pero, como dice @jperovic, solo admite un pequeño conjunto de teclas predefinidas en la matriz de opciones ... No he probado su solución todavía ... pero lo haré es ... gracias de todos modos! – Throoze

+4

Esta solución admite cualquier clave que desee usar, simplemente debe reemplazar el método 'getDefaultOptions'. – eagleoneraptor

+0

Quizás esta respuesta no sea adecuada para el autor de la pregunta, pero seguramente me ha sido útil. Por eso, +1. :) – Sasa

9

Utilizando Symfony 2.8, I tuvo éxito al usar la solución propuesta extendiendo el método configureOptions().

class ElementType extends AbstractType 
{ 
    // ... 

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

que necesitaba usar el ElementType, como una colección y forma embebida. Me di cuenta de que no era posible pasar la my_custom_option_parameter a la CollectionType, porque no personalizo configureOptions() de CollectionType, pero de mi ElementType. Si necesita pasar el my_custom_option_parameter a través de CollectionType, puede tener éxito definiendo my_custom_option_parameter en entry_options (consulte Documentación CollectionType Field) matriz de CollectionType.

Ejemplo pasando my_custom_option_parameter a través de 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

Utilizando Symfony 3, yo era capaz de pasar opciones de encargo para la forma mediante el establecimiento de una opción por defecto en el OptionsResolver inyectado en método configureOptions de mi clase de tipo de forma:

En el controlador:

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

Por lo tanto, parece que puede definir un contrato con su formulario y el proveedor de datos para establecer datos arbitrarios en el formulario.

he implementado simplemente con éxito este procedimiento. Tenga en cuenta que en el viaje de regreso, dado que ha configurado 'mapped' => false, en formBuilder, $form->getData() no devolverá la selección. Para obtener el valor seleccionado:

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

en su controlador. Por qué esto está más allá de mí . .

2

basándose en @pulzarraider respuesta que crea código con cambios de Symfony 3.

Es necesario cambiar

OptionsResolverInterface para OptionsResolver

FormBuilder para FormBuilderInterface

En mi 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; 
    } 
} 
Cuestiones relacionadas