En un desarrollo con Symfony2 en el que estamos trabajando actualmente, se nos presentó la necesidad de mostrar al usuario un formulario de creación distinto al de la edición de un elemento.
Se trata de gestionar proyectos y lo que pretendíamos es que la gestión de los mismos fuera lo más ágil posible, por lo que para crear uno únicamente es necesario introducir el título y posteriormente, si el usuario lo desea, puede editar el proyecto e incluir más información en el resto de campos.
La clase completa del formulario sería la siguiente:
<?php
namespace Vabadus\VabadusBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ProyectoType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('titulo')
->add('descripcion')
->add('cliente')
->add('fecha_entrega')
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Vabadus\VabadusBundle\Entity\Proyecto'
));
}
/**
* @return string
*/
public function getName()
{
return 'vabadusbundle_proyecto';
}
}
De esta forma, al instanciar la clase, siempre mostraríamos el mismo formulario, tanto si estuviéramos creando un proyecto como si lo estuviéramos editando. Como ya hemos dicho, nosotros necesitábamos un formulario diferente en la creación, en el que mostrásemos únicamente el campo titulo, y otro diferente en la edición, incluyendo ya todos los campos. Para poder llevar esto a cabo, nada mejor que el componente Event Dispatcher que incluye Symfony2.
Para conseguir esto lo que hicimos fue delegar el control para mostrar los campos a un Event Subscriber, que se encargase de mostrar el resto de campos, únicamente si estamos editando el elemento.
La clase del formulario quedaría de la siguiente manera:
<?php
namespace Vabadus\VabadusBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\ComponentForm\FormBuilderInterface;
use Symfony\ComponentOptionsResolver\OptionsResolverInterface;
use Vabadus\VabadusBundle\Form\EventListener\IncluyeRestoCamposSubscriber;
class ProyectoType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('titulo')
->addEventSubscriber(new IncluyeRestoCamposSubscriber())
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Vabadus\VabadusBundle\Entity\Proyecto'
));
}
/**
* @return string
*/
public function getName()
{
return 'vabadusbundle_proyecto';
}
}
Y el Event Subscriber:
<?php
namespace VabadusVabadusBundleFormEventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class IncluyeRestoCamposSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if ($data->getId()) {
$form->add('descripcion');
$form->add('cliente');
$form->add('fecha_entrega');
}
}
}
En el método getSubscribedEvents(), se le indica al dispatcher que cuando se produzca el evento form.pre_set_data (FormEvents::PRE_SET_DATA) se tiene que llamar al método preSetData. Y en este método se comprueba si se está editando el objeto, si $data->getId() no devuelve null, con lo que se crean el resto de campos del formulario.