7

Is there any way to "eagerly load" Craft element relations a la Yii's ActiveRelation "with" function?

http://www.yiiframework.com/doc/api/1.1/CActiveRecord#with-detail

This seems like a very handy way to request one big query instead of many small ones in cases where you know up front that you are going to be using all the relations.

** UPDATE **

Okay after experimenting with this, I guess my real question should have been, is there any way to do this kind of thing at the ElementCriteriaModel level, taking advantage of Craft relational fields.

For instance, I want to get a list of children of a Structure entry, along with all the assets in a field:

foreach ($entry->children->find() as $child) {
    // do something with $child->assetsField...
}

Is there any way to load those assets in one big query rather than individually for each child?

  • Which “relations” are you referring to? Active record relations (e.g. what the with() method is for), or Craft element relations? – Brandon Kelly Oct 16 '14 at 20:21
  • Sorry, I should have made it clear. I'm talking about Craft element relations. Edited the question to clarify. – Chris Lewis Oct 17 '14 at 17:19
7

This feature has now made it into Craft core as of version 2.6.

See this link for documentation on the subject:
https://craftcms.com/docs/templating/eager-loading-elements

| improve this answer | |
6

I've been thinking about ways to achieve this recently, and I've put together a basic proof-of-concept plugin for fetching one level of relations for a collection of elements, with no more than two extra queries for each element type.

One query to get the IDs of the related elements, and then another to actually fetch and return the elements with the ElementsService.

The plugin then matches those related elements back to the entries through a dynamically-added fetched() method.

Say you want to fetch all the Assets related through the mainImage and additionalImages fields, over a collection of product entries:

{% set entries = craft.entries.section('products').find %}
{% do craft.fetch.assets(entries, 'mainImage, additionalImages') %}

{% for entry in entries %}
    {% if entry.fetched('mainImage')|length %}
        <img src="{{ (entry.fetched('mainImage')|first).getUrl('large') }}"> 
    {% endif %}

    {% for image in entry.fetched('additionalImages') %}
        <img src="{{ image.getUrl('medium') }}"> 
    {% endfor %}
{% endfor %}

I wouldn't say it's necessarily production-ready yet, but I've thrown it up on Github - https://github.com/mdcpepper/fetch

| improve this answer | |
  • Very cool Mike! I think something like this is definitely on the right track. – Peter Tell Mar 4 '15 at 16:16
  • As noted in another answer, this functionality is now in Craft core, as of version 2.6. – Simon East Aug 5 '16 at 2:44
3

Sure thing.

$groupRecord = FieldGroupRecord::model()->with('fields')->findById($groupId);

That will eager load the related data from the "fields" table with the "fieldgroups" table.

| improve this answer | |
  • Oh duh, I don't know how I missed that Craft Records inherit that. I'll experiment. Thanks! – Chris Lewis Oct 17 '14 at 17:20
  • After some experimentation, I've updated the question to better reflect what I should have asked originally. – Chris Lewis Oct 19 '14 at 14:44
  • Or, if there is an EntryRecord-based way to eagerly load relations from a Craft field, I'll happily take that :) e.g. the equivalent of this: $entry->children->with('assetsField')->find() – Chris Lewis Oct 19 '14 at 14:53
  • I'm actually curious about this too as it relates to grabbing entries and pulling in their associated relationships. i.e., for an entry that has "x" associated images and "x" associated entries, eager load all those relationships in one (or two) DB calls – Peter Tell Dec 15 '14 at 22:03

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.