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.