11 de febrero de 2013

Symfony: Limitaciones de tipo de campo entity y prefetch de las entidades asociadas

Cualquiera que haya trabajado con Symfony y se haya visto en la necesidad de añadir un campo en un formulario que haga referencia a una entidad se habrá visto en la situación de que la única opción posible es usar el tipo 'entity'. Este tipo tienes dos grandes problemas:

  • Solo permite mostrar el campo mediante checkboxes, radiobuttons o selects, donde todas las opciones posibles se muestran para que el usuario escoja alguna en concreto. Esto dificulta mucho la interacción en casos como el de recuperar una entidad vía AJAX y vincularla al formulario.
  • La eficiencia de lo anterior es nula, porque obliga a recuperar todos los valores posibles de la entidad a la hora de mostrar el campo. Imagina que necesitas un campo usuario y tienes más de 5000 en tu base de datos. Sería inviable usar el tipo entity.
Este es un tema que lleva dando vueltas por los repositorios de Symfony desde hace 2 años. Una solución es la propuesta por el usuario Gregwar en este PR https://github.com/symfony/symfony/pull/1951/, que añade el tipo 'entity_id'. Del ejemplo de la misma página:
$builder->add('city', 'entity_id', array(
            'query_builder' => function($repository, $id) {
                return $repository->createQueryBuilder('c')
                    ->where('c.id = :id AND c.available = 1')
                    ->setParameter('id', $id);
            },  
            'class' => 'Gregwar\TestBundle\Entity\City',
            'required' => false,
            'hidden' => true
        )); 
Con este tipo es posible tener un campo de texto o un campo oculto en el que poder insertar automáticamente el ID de una entidad, olvidándonos de selects, radiobuttons o checkboxes, y sin hacer prefetchs de las entidades. Yo llevo usándolo desde hace 8 meses y me ha resuelto bastantes problemas.

Aunque hay bastantes solicitudes para hacer oficial este PR, parece que finalmente la solución oficial va a ser la de añadir un atributo widget al tipo entity, como se detalla aquí https://github.com/symfony/symfony/issues/6602 :

I think that we should add two new options widget and delimiter to ChoiceType.
  • widget can be one of the values selectcheckboxradio and text
  • delimiter can be any single character
Behavior:
  • widget = 'select': This is equivalent to expanded = false right now.
  • widget = 'checkbox'multiple must not be set to false. Otherwise equivalent to expanded = true.
  • widget = 'radio'multiple must not be set to true. Otherwise equivalent to expanded = true.
  • widget = 'text': A text input is shown.
    • if multiple is false, the input must equal one of the predefined choices.
    • if multiple is true, the input is split by the character defined in delimiter (a comma by default), then each value is trimmed (unless trim is false). Each resulting input must equal one of the predefined choices.

Solución bastante más genérica y limpia, y que incluye el tipo de widget text, que combinado con el atributo multiple soluciona el problema de poder referenciar entidades "manualmente". Lo que no aclara esta solución es si seguirá haciendo prefetch o no de todas las entidades posibles. A día de hoy este debate sigue abierto en Github.

4 comentarios:

Fernando dijo...

Hola, puedes mostrar un ejemplo o pequeño tutorial, de su uso ? ... del uso de este bundle? . te lo agardeceria bastante, ya que yo recupero 11 entidades distintas y algunas tiene mas de 1000 registros, con esto se utiliza el autocomplete de jqeury? -- muchas gracias y saludos

arsuceno dijo...

Hola Fernando,

¿A qué tipo de tutorial te refieres? Si te refieres al uso del tipo entity_id junto con el autocomplete de jQuery, la clave está en que usando ese tipo vas a tener un campo de tipo texto que después se vinculará con una entidad. A ese campo de tipo texto le puedes dar funcionalidad de autocomplete indicámdpñe una fuente que te devuelva en JSON el id y el texto que quieras usar como value y label respectivamente. Si me das más detalles te intento echar una mano.

pakmetal dijo...

HOla, gracias por tu respuesta, eso mismo que dices hice, solo que usando otro método .... de igual forma alguna duda que tenga sobre algun tema mencionado aqui, te contactare. de antemano muchas gracias........

pakmetal dijo...
Este comentario ha sido eliminado por el autor.