¿Cómo establecer el valor predeterminado para el campo de formulario en Symfony2?

137

¿Hay una manera fácil de establecer un valor predeterminado para el campo de formulario de texto?

Ondrej Slinták
fuente
1
sí, pero las respuestas dadas en esta pregunta no son satisfactorias / no funcionan ... Agregaré una "Edición" para explicar por qué :-)
herrjeh42
Parece que la solución 'perfecta' que busca es que un campo tenga una opción 'default_value'. La cosa es que actualmente no es así, así que no creo que la solución perfecta que estás buscando exista actualmente. Lo único que ofrece Symfony (ver el enlace) es la opción de datos. Entonces el if-then es el único enfoque que puedo ver en el cajero automático. Incluso si hubiera una opción 'default_value' en el campo en sí, imagino que esencialmente haría lo mismo internamente de todos modos.
crysallus
Además, he corregido mi respuesta en el enfoque 2 según mis comentarios debajo. Si eso soluciona el problema de sintaxis que mencionó en el punto 2, es posible que desee editar ese comentario. O hágame saber cuál es el problema y solucionaré mi respuesta.
crysallus
1
@Crone esta pregunta se hizo 2 años antes
Ondrej Slinták
1
@ OndrejSlinták No voté para cerrar tampoco como engañado, pero para tu información: no importa cuál vino primero, " Si la nueva pregunta es mejor o tiene mejores respuestas, entonces vota para cerrar la anterior como duplicado del nuevo. "
Jeff Puckett

Respuestas:

105

Se puede usar fácilmente durante la creación con:

->add('myfield', 'text', array(
     'label' => 'Field',
     'empty_data' => 'Default value'
))
webda2l
fuente
11
Para Symfony 2.1 necesitaba cambiar la 'data'clave a'value'
Edd
175
Esto no solo establece un valor predeterminado, sino que siempre forzará el valor en cualquier contexto. No es lo que yo llamaría un "valor predeterminado" ...
Hubert Perron
44
Voté en contra de esta solución ya que no es una solución para el problema (como Hubert Perron mencionó anteriormente). Estoy tratando de obtener una mejor solución en esta publicación stackoverflow.com/questions/17986481/…
herrjeh42
13
Este es el valor inicial, el valor predeterminado esempty_data
Pierre de LESPINAY
3
dataes inútil: sobrescribe el valor guardado. empty_datano muestra el valor, lo usa en el envío de valor vacío y hace que sea imposible guardar las opciones sin marcar.
moldcraft
115

puede establecer el valor predeterminado con empty_data

$builder->add('myField', 'number', ['empty_data' => 'Default value'])
rkmax
fuente
29
La configuración de datos no es la configuración predeterminada. Esta respuesta es la correcta.
Alexei Tenitski
9
Esto parece establecer solo el campo en 1 cuando se envía sin valor. ¿Qué sucede cuando desea que el formulario muestre de manera predeterminada 1 en la entrada cuando no hay ningún valor presente?
Brian
En mis pruebas, empty_data no me permite anular el valor predeterminado de un campo enviado vacío, por ejemplo, si desea guardar en la base de datos como 0 en lugar de NULL. Este error aún es sobresaliente por lo que puedo decir: github.com/symfony/symfony/issues/5906
Chadwick Meyer
63

He contemplado esto varias veces en el pasado, así que pensé en anotar las diferentes ideas que tuve / usé. Algo puede ser útil, pero ninguna es una solución "perfecta" de Symfony2.

Constructor En la Entidad puede hacer $ this-> setBar ('valor predeterminado'); pero esto se llama cada vez que carga la entidad (db o no) y es un poco desordenado. Sin embargo, funciona para cada tipo de campo, ya que puede crear fechas o cualquier otra cosa que necesite.

Si las declaraciones dentro de get's no lo haría, pero tú podrías.

return ( ! $this->hasFoo() ) ? 'default' : $this->foo;

Fábrica / instancia . Llame a una función estática / clase secundaria que le proporciona una entidad predeterminada previamente rellenada con datos. P.ej

function getFactory() {
    $obj = new static();
    $obj->setBar('foo');
    $obj->setFoo('bar');

   return $obj;
}

No es realmente ideal dado que tendrá que mantener esta función si agrega campos adicionales, pero significa que está separando los establecedores de datos / predeterminados y lo que se genera a partir de la base de datos. Del mismo modo, puede tener múltiples getFactories si desea diferentes datos predeterminados.

Entidades extendidas / de reflexión Cree una entidad extendida (por ejemplo, FooCreate extiende Foo) que le proporciona los datos predeterminados en el momento de la creación (a través del constructor). Similar a la idea de Fábrica / instancia, solo un enfoque diferente: prefiero los métodos estáticos personalmente.

Establecer datos antes del formulario de compilación En los constructores / servicios, usted sabe si tiene una nueva entidad o si se completó desde la base de datos. Por lo tanto, es posible llamar a los datos del conjunto en los diferentes campos cuando se toma una nueva entidad. P.ej

if( ! $entity->isFromDB() ) {
     $entity->setBar('default');
     $entity->setDate( date('Y-m-d');
     ...
}
$form = $this->createForm(...)

Eventos de formulario Cuando crea el formulario, establece los datos predeterminados al crear los campos. Anula este uso del detector de eventos PreSetData. El problema con esto es que está duplicando la carga de trabajo del formulario / duplicando el código y haciendo que sea más difícil de mantener / comprender.

Formularios extendidos Similar a los eventos de formulario, pero llama a los diferentes tipos dependiendo de si es una entidad db / new Con esto quiero decir que tiene FooType que define su forma de edición, BarType extiende FooType esto y establece todos los datos en los campos. En su controlador, simplemente elija qué tipo de formulario instigar. Sin embargo, esto es una mierda si tienes un tema personalizado y te gustan los eventos, crea demasiado mantenimiento para mi gusto.

Ramita Puede crear su propio tema y predeterminar los datos utilizando la opción de valor también cuando lo hace por campo. No hay nada que lo detenga envolviendo esto en un tema de formulario si desea mantener sus plantillas limpias y el formulario reutilizable. p.ej

form_widget(form.foo, {attr: { value : default } });

JS Sería trivial llenar el formulario con una función JS si los campos están vacíos. Podría hacer algo con marcadores de posición, por ejemplo. Sin embargo, esta es una mala, mala idea.

Formularios como servicio Para uno de los grandes proyectos basados ​​en formularios que hice, creé un servicio que generaba todos los formularios, realizaba todo el procesamiento, etc. Esto se debía a que los formularios debían usarse en múltiples controladores en múltiples entornos y mientras los formularios se generaron / manejaron de la misma manera, se mostraron / interactuaron de manera diferente (por ejemplo, manejo de errores, redirecciones, etc.). La belleza de este enfoque fue que puede predeterminar los datos, hacer todo lo que necesita, manejar los errores genéricamente, etc. y todo está encapsulado en un solo lugar.

Conclusión Tal como lo veo, te encontrarás con el mismo problema una y otra vez: ¿dónde están los datos predeterminados?

  • Si lo almacena a nivel de base de datos / doctrina, ¿qué sucede si no desea almacenar el valor predeterminado cada vez?
  • Si lo almacena en el nivel de entidad, ¿qué sucede si desea reutilizar esa entidad en otro lugar sin ningún dato?
  • Si lo almacena en el Nivel de entidad y agrega un nuevo campo, ¿desea que las versiones anteriores tengan ese valor predeterminado al editarlo? Lo mismo ocurre con el valor predeterminado en el DB ...
  • Si lo almacena en el nivel de formulario, ¿es obvio cuando viene a mantener el código más tarde?
  • Si está en el constructor, ¿qué sucede si usa el formulario en varios lugares?
  • Si lo lleva al nivel JS, ha ido demasiado lejos: los datos no deberían estar en la vista, no importa JS (e ignoramos la compatibilidad, los errores de representación, etc.)
  • El servicio es excelente si, como yo, lo está utilizando en varios lugares, pero es excesivo para un simple formulario de agregar / editar en un sitio ...

Con ese fin, he abordado el problema de manera diferente cada vez. Por ejemplo, una opción de "boletín" de formulario de suscripción se configura fácilmente (y lógicamente) en el constructor justo antes de crear el formulario. Cuando estaba creando colecciones de formularios que estaban vinculados entre sí (por ejemplo, qué botones de radio en diferentes tipos de formularios vinculados entre sí), entonces utilicé Event Listeners. Cuando construí una entidad más complicada (por ejemplo, una que requería hijos o muchos datos predeterminados), utilicé una función (por ejemplo, 'getFactory') para crear su elemento cuando lo necesito.

No creo que haya un enfoque "correcto" ya que cada vez que he tenido este requisito ha sido ligeramente diferente.

¡Buena suerte! Espero haberte dado algo de reflexión en cualquier caso y no divagar demasiado;)

stefancarlton
fuente
¿podría darnos un poco más de detalle sobre lo que quería decir con "un servicio que generó todos los formularios"? También estoy trabajando en un proyecto realmente centrado en el formulario en este momento y sería genial tener diferentes perspectivas sobre él.
user2268997
2
cuando se usa la doctrina, no se llama a los constructores cuando se carga una entidad desde la base de datos.
NDM
43

Si necesita establecer el valor predeterminado y su formulario se relaciona con la entidad, entonces debe usar el siguiente enfoque:

// buildForm() method
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
    ...
    ->add(
        'myField',
        'text',
        array(
            'data' => isset($options['data']) ? $options['data']->getMyField() : 'my default value'
        )
    );
}

De lo contrario, myFieldsiempre se establecerá en el valor predeterminado, en lugar de obtener el valor de la entidad.

Dmitriy
fuente
En el caso de matrices en lugar de entidades, simplemente reemplace $options['data']->getMyField()con$option['data']['myField']
ggg
3
Esta es la forma correcta de agregar / actualizar, creo. Pero odio que Symfony lo haga demasiado complejo.
Yarco
Esta es la única buena respuesta. No entiendo otras respuestas cuando miro el documento. empty_data: Esta opción determina qué valor devolverá el campo cuando el valor enviado esté vacío. No establece un valor inicial
Vincent Decaux
16

Si su formulario está vinculado a una entidad, simplemente establezca el valor predeterminado en la entidad usando el método de construcción:

public function __construct()
{
    $this->field = 'default value';
}
Hubert Perron
fuente
Aun así, su formulario puede tener campos adicionales no asignados a su entidad ( 'mapped' => false). Uso setData(...)para estos.
Dizzley
12

Enfoque 1 (de http://www.cranespud.com/blog/dead-simple-default-values-on-symfony2-forms/ )

Simplemente establezca el valor predeterminado en su entidad, ya sea en la declaración de variable o en el constructor:

class Entity {
    private $color = '#0000FF';
    ...
}

o

class Entity {
    private $color;

    public function __construct(){
         $this->color = '#0000FF';
         ...
    }
    ...
}

Enfoque 2 de un comentario en el enlace anterior, y también la respuesta de Dmitriy (no la aceptada) de ¿Cómo establecer el valor predeterminado para el campo de formulario en Symfony2?

Agregue el valor predeterminado al atributo de datos al agregar el campo con FormBuilder, adaptado de la respuesta de Dmitriy.

Tenga en cuenta que esto supone que la propiedad tendrá y solo tendrá el valor nulo cuando se trata de una entidad nueva y no existente.

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('color', 'text', array(
            'label' => 'Color:',
            'data' => (isset($options['data']) && $options['data']->getColor() !== null) ? $options['data']->getColor() : '#0000FF'
        )
    );
}
crysallus
fuente
El primero funciona (¡gracias!), El segundo no (para mí): $ options ["data] siempre está configurado, por lo que el valor predeterminado nunca se utilizará. Todavía me pregunto si la solución número 1 es la forma prevista. para hacerlo ...
herrjeh42
Tienes razón acerca de que siempre se establecen $ options ['datos']. Si no inicializa el campo de entidad, puede probar nulo en el campo, por ejemplo. 'data' => $ options ['data'] -> getColor ()! == null? etc ... Eso supone que nulo no es un valor válido para el campo de color, por lo que las entidades existentes nunca tendrían un valor nulo para ese campo.
crysallus
ah, estúpido: lo intenté con 'isset ($ $ options [' data '] -> getColor ())', recibí un mensaje de error sobre "no está permitido usarlo en contextos de escritura" y olvidé que tengo que compruébalo de manera diferente :-)
herrjeh42
1
En realidad, parece haber ocasiones en que la entrada de datos no está configurada. Es más seguro probar ambos, es decir, isset ($ options ['data']) && $ options ['data'] -> getColor ()! == null? ...
crysallus
9

Puede establecer un valor predeterminado, por ejemplo, para el formulario message, como este:

$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
    ->add('name', 'text')
    ->add('email', 'email')
    ->add('message', 'textarea')
    ->add('send', 'submit')
    ->getForm();

En caso de que su formulario esté asignado a una Entidad, puede ir así (por ejemplo, nombre de usuario predeterminado):

$user = new User();
$user->setUsername('John Doe');

$form = $this->createFormBuilder($user)
    ->add('username')
    ->getForm();
Gottlieb Notschnabel
fuente
2
Prefiero este método, especialmente porque en la mayoría de las aplicaciones está creando un formulario y pasando una entidad con la que trata el formulario.
Skrilled
9

Una solución general para cualquier caso / enfoque, principalmente mediante el uso de un formulario sin clase o cuando necesitamos acceso a cualquier servicio para establecer el valor predeterminado:

// src/Form/Extension/DefaultFormTypeExtension.php

class DefaultFormTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if (null !== $options['default']) {
            $builder->addEventListener(
                FormEvents::PRE_SET_DATA,
                function (FormEvent $event) use ($options) {
                    if (null === $event->getData()) {
                        $event->setData($options['default']);
                    }
                }
            );
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('default', null);
    }

    public function getExtendedType()
    {
        return FormType::class;
    }
}

y registre la extensión del formulario:

app.form_type_extension:
    class: App\Form\Extension\DefaultFormTypeExtension
    tags:
        - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }

Después de eso, podemos usar la defaultopción en cualquier campo de formulario:

$formBuilder->add('user', null, array('default' => $this->getUser()));
$formBuilder->add('foo', null, array('default' => 'bar'));
yceruto
fuente
Esta debería haber sido aceptada como la mejor respuesta (actualizada)
medunes
7

No utilizar:

'data' => 'Default value'

Lea aquí: https://symfony.com/doc/current/reference/forms/types/form.html#data

"La opción de datos siempre anula el valor tomado de los datos de dominio (objeto) cuando se procesa. Esto significa que el valor del objeto también se anula cuando el formulario edita un objeto ya persistente, haciendo que pierda su valor persistente cuando se envía el formulario".


Use lo siguiente:

Digamos, para este ejemplo, tiene un Entity Foo, y hay un campo "activo" (en este ejemplo es CheckBoxType, pero el proceso es el mismo para cualquier otro tipo), que desea que se verifique de forma predeterminada

En su clase FooFormType agregue:

...
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
...
public function buildForm( FormBuilderInterface $builder, array $options )
{
    ...

    $builder->add('active', CheckboxType::class, array(
        'label' => 'Active',
    ));

    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function(FormEvent $event){                 
            $foo = $event->getData();
            // Set Active to true (checked) if form is "create new" ($foo->active = null)
            if(is_null($foo->getActive())) $foo->setActive(true);
        }
   );
}
public function configureOptions( OptionsResolver $resolver )
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle:Foo',
    ));
}
cure85
fuente
¡Esto es dinero! Use el detector de eventos de formulario para verificar sus valores antes de omitirlos. Esta debería ser la respuesta aceptada para los valores predeterminados en sus formularios porque funciona tanto para acciones nuevas como para acciones de edición.
tlorens
Esta es la forma correcta de manejar esto y esta debería ser la respuesta aceptada.
Bettinz
Lo que mencionas al principio no es cierto si usas un condicional / ternario. De esta manera:'data' => $data['myfield'] ?? 'Default value'
xarlymg89
6
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if ($data == null) {
         $form->add('position', IntegerType::class, array('data' => 0));
     }

});
ziiweb
fuente
Esta es una buena solución. Llamar en $event->setData()lugar de leer el campo podría hacerlo aún mejor.
user2268997
5

Mi solución:

$defaultvalue = $options['data']->getMyField();
$builder->add('myField', 'number', array(
            'data' => !empty($defaultvalue) ? $options['data']->getMyField() : 0
        )) ;
trocolo
fuente
4

Solo para que entienda el problema.

Desea ajustar la forma en que se crea el formulario en función de los datos de su entidad. Si la entidad se está creando, utilice algún valor predeterminado. Si la entidad existe, use el valor de la base de datos.

Personalmente, creo que la solución de @ MolecularMans es el camino a seguir. De hecho, establecería los valores predeterminados en el constructor o en la declaración de propiedad. Pero no parece que te guste ese enfoque.

En su lugar, puede seguir esto: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Cuelga un oyente en su tipo de formulario y luego puede examinar su entidad y ajustar el constructor-> agregar declaraciones en consecuencia en función de una entidad nueva o existente. Aún necesita especificar sus valores predeterminados en algún lugar, aunque podría codificarlos en su escucha. O páselos al tipo de formulario.

Sin embargo, parece mucho trabajo. Es mejor simplemente pasar la entidad al formulario con sus valores predeterminados ya establecidos.

Cerad
fuente
4

Si está utilizando un FormBuilderen Symfony 2.7 para generar el formulario, también puede pasar los datos iniciales al createFormBuildermétodo del Controler

$values = array(
    'name' => "Bob"
);

$formBuilder = $this->createFormBuilder($values);
$formBuilder->add('name', 'text');
Beto
fuente
3

A menudo, para los valores predeterminados de inicialización de la forma, uso fixtures. Por supuesto, este camino no es más fácil, pero sí muy cómodo.

Ejemplo:

class LoadSurgeonPlanData implements FixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $surgeonPlan = new SurgeonPlan();

        $surgeonPlan->setName('Free trial');
        $surgeonPlan->setPrice(0);
        $surgeonPlan->setDelayWorkHours(0);
        $surgeonPlan->setSlug('free');

        $manager->persist($surgeonPlan);
        $manager->flush();        
    }   
}

Sin embargo, el campo de tipo Symfony tiene los datos de la opción .

Ejemplo

$builder->add('token', 'hidden', array(
    'data' => 'abcdef',
));
Mikhail Shchedrakov
fuente
3

Hay una manera muy simple, puede establecer valores predeterminados como aquí:

$defaults = array('sortby' => $sortby,'category' => $category,'page' => 1);

$form = $this->formfactory->createBuilder('form', $defaults)
->add('sortby','choice')
->add('category','choice')
->add('page','hidden')
->getForm();
alsaciano
fuente
3

Si configura 'datos' en su formulario de creación, este valor no se modificará cuando edite su entidad.

Mi solución es:

public function buildForm(FormBuilderInterface $builder, array $options) {
    // In my example, data is an associated array
    $data = $builder->getData();

    $builder->add('myfield', 'text', array(
     'label' => 'Field',
     'data' => array_key_exits('myfield', $data) ? $data['myfield'] : 'Default value',
    ));
}

Adiós.

Quentin Machard
fuente
¡Mucho más útil que una respuesta aceptada! Si usa PHP7 + puede hacerlo aún más 'data' => $data['myfield'] ?? 'Default value',
ordenado
Tiene un error tipográfico en la función array_key_exists ()
Deadpool
1

Los valores predeterminados se establecen configurando la entidad correspondiente. Antes de vincular la entidad a formar, configure su campo de color en "# 0000FF":

// controller action
$project = new Project();
$project->setColor('#0000FF');
$form = $this->createForm(new ProjectType(), $project);
Hombre molecular
fuente
este enfoque funciona, pero tiene la desventaja de que tiene que hacerlo cada vez que usa la clase de formulario y es muy detallado (muchas declaraciones establecidas). Como el componente de formulario es muy elegante, debe haber algo más. Pero gracias de todos modos :-)
herrjeh42
@ jamie0726 En mi opinión, es responsabilidad del controlador establecer los valores del objeto siempre que sea nuevo o recuperado. De esta forma, puede hacer que el formulario se use en diferentes situaciones con diferentes comportamientos, por ejemplo, el nuevo color puede cambiar debido a que el usuario tiene un rol de administrador o supergerente, y dado que esta es una lógica de negocios, eso debe ser controlado por el controlador o un servicio, no el formulario. Entonces, como dijo Cerad, también prefiero esta solución. Siempre puede crear un servicio para establecer esos valores predeterminados y en el controlador usar ese servicio manteniéndolo SECO.
saamorim
Esta es la solución que elegí, porque creo que se ajusta a la lógica. Los controladores generados tienen diferentes métodos para crear formularios EDITAR y CREAR, y allí es donde configuro los datos predeterminados / iniciales para la nueva entidad.
alumi
1

Si ese campo está vinculado a una entidad (es una propiedad de esa entidad), solo puede establecer un valor predeterminado para él.

Un ejemplo:

public function getMyField() {
    if (is_null($this->MyField)) {
        $this->setMyField('my default value');
    }
    return $this->MyField;
}
Andrei Sandulescu
fuente
1

Por lo general, solo configuro el valor predeterminado para un campo específico en mi entidad:

/**
 * @var int
 * @ORM\Column(type="integer", nullable=true)
 */
protected $development_time = 0;

Esto funcionará para nuevos registros o si solo actualiza los existentes.

matotej
fuente
Esto no parece funcionar cuando 'empty_data'se utiliza una devolución de llamada para permitir parámetros de constructor en la entidad.
NDM
1

Como Brian preguntó:

empty_data parece establecer solo el campo en 1 cuando se envía sin valor. ¿Qué sucede cuando desea que el formulario muestre de manera predeterminada 1 en la entrada cuando no hay ningún valor presente?

puede establecer el valor predeterminado con empty_value

$builder->add('myField', 'number', ['empty_value' => 'Default value'])
Snowirbis
fuente
0

Resolví este problema, agregando valor en attr :

->add('projectDeliveringInDays', null, [
    'attr' => [
          'min'=>'1',
          'value'=>'1'
          ]
     ])
Kaxa
fuente