My Doctrine entity Section
has a self-referencing association parent
and a slug
property. I made this function (inside the section repository) for returning a section given its web path:
/**
* Finds a section by its path, i.e. /a/b/c.
*
* @param string $path
* @return null|\Application\Entity\Section
*/
public function findOneByPath($path)
{
// Slug exploding so we get array("a", "b", "c")
if (!($slugs = explode('/', $path))) {
return null;
}
// Get the slug for the leaf (at least) i.e. "c"
$leafSlug = array_pop($slugs);
// Query builder for selecting the leaf
$qb = $this->createQueryBuilder('s0');
$qb->select('s0')
->where($qb->expr()->eq('s0.slug', ':s0_slug'))
->setParameter('s0_slug', $leafSlug);
// Dynamical adding joins in reverse order i.e. array("b", "a")
$idx = 0;
foreach (array_reverse($slugs) as $slug) {
$qb->innerJoin("s{$idx}.parent", "s".++$idx)
->andWhere($qb->expr()->eq("s{$idx}.slug", ":s{$idx}_slug"))
->setParameter("s{$idx}_slug", $slug);
}
return $qb->getQuery()->getOneOrNullResult();
}
It's working fine but I can't understand why Doctrine is making two queries (log file):
[2013-09-07 15:26:30] App.DEBUG: SELECT s0_.id AS id0, s0_.slug AS slug1 [...]
FROM section s0_ INNER JOIN section s1_ ON s0_.parent_id = s1_.id
WHERE (s0_.slug = ? AND s1_.slug = ?) ["b","a"] []
[2013-09-07 15:26:30] App.DEBUG: SELECT t0.id AS id1, t0.slug AS slug2 [...]
FROM section t0 WHERE t0.id = ? ["1"] []
As you can see the first one is that with INNER JOIN and it's correnct. The second is useless I suppose... or I'm missing something? By the way, 1
is the id
of "a"...
EDIT: this is not happening when the foreach
isn't executed (i.e. findOneByPath('a')
). There are n + 1
queries (n
unwanted) as the number of foreach
iterations (with /a/b/c/d
four queries).