Allow plugins to implement custom eager loading #4220
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Eager loading is a great feature of Craft, basically the user marks relations / fields he is going to access on queries and the CMS can preload those fields in oder to speed up things. However, the current implementation is very strict on how this works, basically a field can only eager load one element type, the field will be completely replaced by the eager loaded elements and the field must supply the element ids in a certain fashion; all this magic happens in one big method.
Suggestion
I guess it would be quite difficult to extend the current technique so it fits multiple purposes, so I would like to suggest to open up a way for fields to take care of eager loading stuff on their behalf and bypass the default behavior.
Simple approach
Currently fields can implement the interface
EagerLoadingFieldInterface
whose methodgetEagerLoadingMap
can either return an array if elements should be eager loaded orfalse
if for some reason the field is sure all values will be empty. No matter what it returns, the core will set the eager loaded property here on all elements and we have no way to prevent this. As a simple solution, allowgetEagerLoadingMap
to return something (likenull
ortrue
) to signal that it will take care of eager loading by itself.Usage example
I'm the author a a link field plugin and I've noticed the field can produce an immense amount of additional database hits if a lot of element links must be fetched (e.g. when building a navigation that contains redirect pages). Unfortunately I cannot use the default eager loading path as a) the field can contain different element links (e.g. links to assets and elements) and b) would replace the link model with the eager loaded elements. I've highjacked the
with
property (by looking for my fields handle inField::modifyElementsQuery
and filtering it out) and was able to greatly improve the performance, but the current implementation feels more than wacky.