Repository navigation
[6.x] Cache Entry::descendants() per request - #15645
Open
joshuablum wants to merge 1 commit into
Open
joshuablum wants to merge 1 commit into
joshuablum wants to merge 1 commit into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Since #14773,
Entry::descendants()loads the localization tree with one batched query per level but only the first level (directDescendants()) is cached.Entry::in()resolves through$this->root()->descendants(), so everyin()call queries the deeper levels again. Code that callsin()once per site, like thelocalestag or addons building hreflang tags, runs O(sites*depth) queries on every page view.Using the Eloquent driver, 10
in()calls on an entry with nested localizations ran 24 queries, and 30 calls ran 74.This PR caches the whole tree (
entry-all-descendants-{id}) so the descendant queries run once per entry per request. The batched loading from #14773 is unchanged.descendants()anddirectDescendants()return copies, so callers that modify the result can't corrupt the cache. Previously,descendants()returned the cached first-level collection itself when there were no deeper levels.flushDescendantsCache()clears both cache keys for an entry and its ancestors. It's called on save, delete,deleteDescendants()anddetachLocalizations().getOriginal('origin').delete()didn't clear any cache before, so an origin kept listing a deleted localization for the rest of the request. That's fixed as part of this.Facades\Entry::save($entry)) skips the clearing.Related: statamic/seo-pro#694 works around the same issue in SEO Pro by resolving an entry's localizations once per cascade. This PR fixes it in core so every caller of
in()benefits.