Blog


Entidad como campo oculto en formulario Symfony2

ENTIDAD COMO CAMPO OCULTO EN FORMULARIO SYMFONY2

12 / 12 / 2013 Symfony

En este artículo vamos a ver cómo solucionar un problema típico cuando trabajamos con formularios Symfony2 y necesitamos incluir una entidad relacionada como campo oculto. Para ello, vamos a hacer uso de Data Transformers, que nos permtirá usar un dato de una forma diferente a como se creó.

Pongamos el caso que tenemos una relación 1:N entre Tarea y Proyecto. Estamos gestionando un proyecto y queremos crearle una nueva tarea, para lo que necesitaremos incluir en el formulario de tarea un campo oculto con el identificador del proyecto que estamos gestionando.

Lo primero que tenemos que hacer es crear la clase base que transforme una entidad a su id (un número entero), clase que podremos usar para cualquier entidad de nuestro proyecto:


<?php

namespace Vabadus\VabadusBundle\Form\DataTransformer;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

class EntityToIntTransformer implements DataTransformerInterface
{
    private $om;
    private $class;

    public function __construct(ObjectManager $om, $class)
    {
        $this->om    = $om;
        $this->class = $class;
    }

    public function transform($entity)
    {
        if (null === $entity) {
            return;
        }

        return $entity->getId();
    }

    public function reverseTransform($id)
    {
        if (!$id) {
            return null;
        }

        $entity = $this->om
                       ->getRepository($this->class)
                       ->find($id);

        if (null === $entity) {
            throw new TransformationFailedException();
        }

        return $entity;
    }
}

Una vez que tenemos listo el tranformador, ya podemos usarlo en cualquier campo de los formularios de nuestro proyecto Symfony. Pero para que sea más fácilmente reutilizable, vamos a crear un tipo de campo de formulario personalizado en el que usaremos el transformador:


<?php

namespace Vabadus\VabadusBundle\Form\Type;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Vabadus\VabadusBundle\Form\DataTransformer\EntityToIntTransformer;

class EntityIdType extends AbstractType
{
    private $om;

    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new EntityToIntTransformer(
            $this->om,
            $options['class']
        );

        $builder->addModelTransformer($transformer);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'class'                     => null,
            'invalid_message' => 'La entidad no existe.',
        ));
    }

    public function getParent()
    {
        return 'hidden';
    }

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

Registramos esta nueva clase como un servicio para poder utilizar el nuevo tipo de campo en cualquier formulario:


services:
    vabadus.form.type.entity_id:
        class: Vabadus\VabadusBundle\Form\Type\EntityIdType
        arguments: [@doctrine.orm.entity_manager]
        tags:
            - { name: form.type, alias: entity_id }

Si todavía no lo tuviéramos, importamos el services.yml del bundle sobre el que estamos trabajando, en el config.yml de la aplicación:


imports:
  - { resource: "@AcmeDemoBundle/Resources/config/services.yml" }

Y ahora sí, cada vez que necesitemos insertar el identificador de una entidad relacionada como un campo oculto en un formulario Symfony, utilizaremos nuestro entity_id. En el ejemplo, el formulario de Tarea sería:


<?php

namespace Vabadus\VabadusBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class TareaType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        ...

        $builder->add('proyecto', 'entity_id', array(
            'class' => 'Vabadus\VabadusBundle\Entity\Proyecto',
        ));

        ...
    }

    ...

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



ARTÍCULOS RELACIONADOS