Optimizando operaciones sobre colecciones Symfony con Criteria

Rutas
Solucionex
06
Sep 24

Cuando estamos desarrollando con Symfony es muy común encontrarse en la situación de tener que ordenar o filtrar una colección de una relacion en una entidad y lo normal es hacerlo en tu código hacer la operación sobre la entidad, otra alternativa sería hacer una query con querybuilder dento del repositorio. Ambas soluciones tienen sus pros y sus contras. La primera te has traído todos los datos y has operado sobre ellos en vez de pedírselo al gestor de la base de datos, en el segundo tienes que instanciar un repositorio que y volver a hacer una consulta sobre unos datos que ya tienes.

Las colecciones Doctrine que se incluyen en Symfony ofrecen una vía para poder hacer estas operaciones sobre una colección y que éstas se hagan en la consulta a la base de datos, se hace mediante la función matching utilizando un objeto Criteria.

Mejor que lo veamos con algo de código, supongamos que tenemos dos entidades Usuario y Comentario con Usuario teniendo una relación OneToMany con Comentario y Comentario teniendo un campo valor y otro visible. Ahora queremos obtener las comentarios de un usuario que son visibles.

$usuario->getComentariosVisibles()

Podemos filtrar la colección

//App\Entity\Usuario.php
public function getComentariosVisibles() {
    return $this->comentarios->filter(function($comentario) {
            return $comentario->isVisible();
        });
}

En este caso estamos iterando sobre todos y cada uno de los comentarios del usuario y desechando aquellos que no nos valen

Podríamos hacer la query con querybuilder

//App\Repository\UsuarioRepository.php
public function getComentariosVisibles(): array
{
    return $this->createQueryBuilder('u')
        ->select('u')
        ->join('u.comentarios', 'c')
           ->andWhere('c.isVisible = :isVisible')
            ->setParameter('isVisible', true)
        ->getQuery()
        ->getResult();
}

O podemos usar Criteria

//App\Entity\Usuario.php
use Doctrine\Common\Collections\Criteria;
public function getComentariosVisibles(): Collection
{
    return $this->comentarios->matching(Criteria::create()
        ->andWhere(Criteria::expr()->eq('isVisible', true))
    );
}

En este caso Doctrine hará la query sobre la base de datos igual que cuando lo hacíamos con querybuilder.

symfony