1

So I have structures that are related in the follwing way:

  • Locations has many Providers
  • Providers has many Health Topics

I know that I can eager load all Locations with related Providers and Health Topics very easily using using something like this:

craft.entries.section('locations').with(['providers.healthTopics']).all()

However how can I eager load the reverse relationship, loading all Health Topics with their related Providers and Locations? The eager loading function seems to go from parent to children but not from children to parent...though I could be missing something there?

2

Ok so here's how I ended up doing this. Essentially querying everything and adding a sourceId and targetId property to each result. In order to get this query to work though, we need to add a behavior to the Entry component to support two new properties, sourceId and targetId.

// This basically left-joins the the relationship table to our sections. This allows us
// to essentially "eager-load" in reverse.
$relatedQuery = Entry::find()
  ->section(['healthTopics', 'providers', 'locations'])
  ->addSelect('relations.targetId')
   ->addSelect('relations.sourceId')
   // You can query to get the field ids here, I just decided to look them up in the db.
    ->leftJoin(
               '{{%relations}} relations' ,
                '([[elements.id]] = [[relations.sourceId]]) AND ([[relations.fieldId]] = 2 OR [[relations.fieldId]] = 5)'
            )
    ->groupBy('elements.id')
    ->all();

    // Same thing here, just looked up the section ids instead of querying for them.
    $healthTopics = ArrayHelper::where($relatedQuery, 'sectionId', '1');
    $providers = ArrayHelper::where($relatedQuery, 'sectionId', '3');
    $locations = ArrayHelper::where($relatedQuery, 'sectionId', '2');

Next, I needed to add a behavior to the Entry component so that it could support having the two new properties we added, sourceId and targetId.

<?php

namespace foo\behaviors;

use yii\base\Behavior;

class EntryBehavior extends Behavior
{
    public $targetId;
    public $sourceId;
}

Event::on(Entry::class, Entry::EVENT_DEFINE_BEHAVIORS, static function (DefineBehaviorsEvent $event) {
    $event->behaviors['entryBehavior'] = ['class' => EntryBehavior::class];
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.