Skip to content

feat: optional keys-for-cache (KFC) support - #280

Open
erikfrerejean wants to merge 6 commits into
6from
feat/keys-for-cache-support
Open

feat: optional keys-for-cache (KFC) support#280
erikfrerejean wants to merge 6 commits into
6from
feat/keys-for-cache-support

Conversation

@erikfrerejean

Copy link
Copy Markdown
Member

What & why

Adds optional out-of-the-box support for silverstripe-terraformers/keys-for-cache (KFC) so grid elements get reliable, auto-invalidating cache keys when the module is installed — without making it a hard dependency. It is added under suggest, and all wiring is guarded by Only: moduleexists.

Approach

The integration is config-only — no PHP, no imports, no PHPStan stubs. KFC already applies its CacheKeyExtension to DataObject globally, so _config/keys-for-cache.yml only:

  • sets has_cache_key: true on GridElement (inherited by Section/Row/Column/ContentElement and any consumer subclass);
  • declares cares downward through the has_many relations (SectionRows, RowColumns, ColumnElements), deliberately avoiding the polymorphic Parent edge. A change to any descendant transitively invalidates its ancestors' keys.

Consumers cache per-section in their own templates: <% loop $Sections %><% cached $CacheKey %>$Me<% end_cached %><% end_loop %>. We do not opt SiteTree into has_cache_key (only classes we own).

Test environment consolidation

The previous per-module app-fluent Docker service is replaced by a single app-modules env that installs all optional modules (Fluent and KFC). Base app stays the zero-optional-deps baseline; app-modules is the everything-optional env. This touches compose.yml, Makefile (make test-modules), composer.modules.json, phpunit.xml.dist (new kfc suite), and CI. Trade-off: the kfc suite runs with Fluent also present (the realistic combined target); the base env still proves "works with nothing optional".

KFC's SS6-compatible release is ^3.0 (1.x/2.x cap at framework ^5).

Not included — owned-media caching (deferred)

Caching media-image edits was dropped: KFC cannot cares about a has_one whose target has no reciprocal relation, and MediaImage/VideoCustomThumbnail point to the shared Image class. Editing media via an element's CMS form re-saves the element (which does invalidate via the downward cares); only editing an in-use Image directly in asset-admin is uncovered. Documented as a known limitation; a per-element owned media model that KFC can traverse is a planned separate project.

Tests

New tests/Integration/KeysForCache/ suite guards: cache-key presence, transitive ancestor invalidation, cross-tree isolation, and draft/live separation. (Invalidation tests use KFC's documented ProcessedUpdatesService::flush() to defeat its per-request dedup; assertions are not weakened.)

Verification (local):

  • Base env, KFC absent: OK (1199 tests, 3919 assertions)
  • Optional-modules env (integration,functional,fluent,kfc): OK (766 tests, 2444 assertions)

Docs

  • docs/architecture/keys-for-cache.md — what activates, the cares graph, the <% cached %> recipe, the Fluent global_key note, the media limitation, and the per-write cost note.
  • New gotcha in CLAUDE.md (via APM sources): editing a single-file bind mount (composer.json) while dev containers run breaks it inside the container until --force-recreate.

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