James Crinkley
James Crinkley

Reputation: 1408

Dynamically eager loading deep relationships with Doctrine

I'm currently working on an API using the following stack;

I'm wanting to integrate the ability to specify, via query parameter, which relationships to include when retrieving an entity/collection, e.g;

[GET] /users?include=friends.addresses

Fractal comes with the ability to handle includes however, as this happens around the serialization point of the response building, each related entity is retrieved via lazy loading, thus triggering additional queries.

Is there a way to tell Doctrine, when retrieving a collection, to dynamically also retrieve relationships specified? Ive seen the following from the Doctrine docs which shows how to dynamically change the fetch mode however this only seems to work with associations on the target entity (friends in the example above) and not deeper relations (addresses of friends in the example).

Thanks!

Upvotes: 2

Views: 1934

Answers (1)

Berry Ligtermoet
Berry Ligtermoet

Reputation: 881

If I remember correctly you can "preload" relations by joining them in rather than letting the lazy loading mechanism handle it. An idea could be to create a service that creates a query builder based on your criteria. This is a crude snippet of what I mean:

class EagerService
{
    protected $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function resolveIncludes($class, $alias, $includes) 
    {
        // Parse includes into an array
        if (strpos($includes, '.') !== false) {
            $relations = explode('.', $includes);
        } else {
            $relations = [$includes];
        }

        // The next relation is owned by the previous one, so we keep track of the previous relation
        $previousRelation = $alias;
        $qb = $em->getRepository($class)->getQueryBuilder($previousRelation);
        foreach ($relations as $relation) {
            // Add inner joins to the query builder referencing the new relation
            $qb->innerJoin("{$previousRelation}.{$relation}", $relation);
            $previousRelation = $relation;
        }

        // Return query builder or the result of the query
        return $qb;
    }
}

Upvotes: 2

Related Questions