TransWikia.com

How do you eager load or join reverse relationships for entries?

Craft CMS Asked by Myles Hyson on February 19, 2021

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?

One Answer

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 foobehaviors;

use yiibaseBehavior;

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];
});

Correct answer by Myles Hyson on February 19, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP