Este caso es un poco difícil de explicar. Vamos a suponer lo siguiente: Tenemos una entidad Factura
y un repositorio FacturaRepository
que tiene una función findFacturas()
. Dicha función recibe un parámetro obligatorio $usuario
de clase Usuario
y otro opcional $filtros
que por defecto es un array vacío. La mencionada función, que está perfectamente testeada y no desea cambiarse, prepara dinámicamente una query DQL teniendo en cuenta los permisos del usuario y un montón de filtros y devuelve un objeto de clase Query
que al ejecutarla devuelve la lista de facturas del usuario.
namespace Company\ContabilidadBundle\Entity; class Factura { //... } class FacturaRepository { public function findFacturas(Usuario $usuario, $filtros = array( )) { //... return $query; } }
Por otro lado, en otra parte de la aplicación, tenemos un formulario en el que necesitamos poder seleccionar una de las facturas del usuario mediante un cuadro de selección (combobox). Para ello lo más lógico es añadir al formulario un campo de tipo entity
. El problema es que que no podemos aprovechar la query que tenemos en nuestro repositorio porque los campos entity se cargan con un QueryBuilder
.
Hoy me he encontrado con este mismo problema. Quedaba totalmente descartado Convertir en un QueryBuilder una query DQL de dos palmos y medio de largo, perfectamente testeada, por su complejidad (y porque no me daba la gana), así que me he puesto a investigar si había alguna forma de convertir o cargar un objeto Query
en un objeto QueryBuilder
. No ha sido fácil pero lo he conseguido...
Este es el resultado:
namespace Company\ContabilidadBundle\Form\Type; class FormularioFormType extends AbstractType { //... public function buildForm(FormBuilderInterface $builder, array $options) { //... $builder->add( 'factura', 'entity', array( 'class' => 'CompanyContabilidadBundle:Factura', 'query_builder' => function(EntityRepository $repository) use($usuario) { $query = $repository->findFacturas($usuario); $qb = $repository->createQueryBuilder('f'); $qb->where($qb->expr()->in('f', $query->getDql())); $qb->setParameters($query->getParameters()); return $qb; } )); } }
Veámoslo paso a paso:
- En primer lugar obtenemos el objeto
Query
del repositorio. Dicho objeto estará listo para ser ejecutado devolviendo el resultado que deseamos. - En segundo lugar extraemos la sentencia DQL y los parámetros del objeto
Query
con las instrucciones$query->getDql()
y$query->getParameters()
. - En último lugar creamos un nuevo objeto
QueryBuilder
y simulamos una subquery como esta:SELECT * FROM Facturas f WHERE f IN (...)
, poniendo la sentencia DQL original en el lugar de los puntos suspensivos.
Es rebuscado pero funciona perfectamente.