Skip to content

[6.x] Cache Entry::descendants() per request - #15645

Open
joshuablum wants to merge 1 commit into
6.xfrom
fix/memoize-entry-descendants
Open

joshuablum wants to merge 1 commit into
6.xfrom
fix/memoize-entry-descendants

Conversation

@joshuablum

Copy link
Copy Markdown
Member

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 every in() call queries the deeper levels again. Code that calls in() once per site, like the locales tag 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() and directDescendants() 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.
  • A new private flushDescendantsCache() clears both cache keys for an entry and its ancestors. It's called on save, delete, deleteDescendants() and detachLocalizations().
  • When a save changes an entry's origin, the previous origin's tree is cleared too, using 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.
  • Like the existing first-level cache, saving or deleting through the repository directly (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.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant