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 select
, checkbox
, radio
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.