Repository navigation
Conversation
Collect cache directives, dependency tags, and reasons for synchronous cache integration consumers at the Craft middleware checkpoint. Preserve privacy and storage restrictions while migrating legacy cache header callers. Amp-Thread-ID: https://ampcode.com/threads/T-43f45309-465e-4cd2-a911-0978bfe4f41d Co-authored-by: Amp <amp@ampcode.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
📚 Storybook previews@craftcms/ui — open Storybook No changed components detected in this Storybook. resources/js — open Storybook No changed components detected in this Storybook. |
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the request-scoped HTTP cache policy API.
No open issues 🎉
What changed in this PR
Adds a request-scoped HTTP cache policy API so Craft cache integrations can consume shared directives, dependency tags, and explanations instead of inferring intent from headers.
Changes:
- Introduces
CacheControl, middleware that applies policy and caps freshness by dependency expiry, and a checkpoint event with a detached policy snapshot. - Migrates template expiry, CSRF, and pending-transform handling from
ResponseHeaders, preserving storage restrictions without supplying a default lifetime. - Adds coverage for middleware ordering, privacy, request isolation, dependency expiry, and integration behavior.
| File | Description |
|---|---|
| tests/Unit/View/BladeDirectives/ResponseDirectiveTest.php | Tests migrated Blade expiry and last-duration-wins behavior. |
| tests/Unit/Twig/Tags/ExpiresTagTest.php | Tests migrated Twig expiry and directive precedence. |
| tests/Unit/Support/HtmlTest.php | Checks CSRF protection through the new middleware. |
| tests/Feature/Image/ImageTransformerTest.php | Tests storage prohibition for pending transforms. |
| tests/Feature/Http/Middleware/SetHeadersTest.php | Updates JSON-response coverage to use the new API. |
| tests/Feature/Http/Middleware/ApplyCacheControlTest.php | Covers policy application, privacy, expiry, isolation, and event consumers. |
| tests/.pest/snapshots/Unit/Twig/Nodes/ExpiresNodeTest/it_compiles_with_static_duration.snap | Updates static expiry compilation output. |
| tests/.pest/snapshots/Unit/Twig/Nodes/ExpiresNodeTest/it_compiles_with_dynamic_expiration.snap | Updates dynamic expiry compilation output. |
| src/Twig/Nodes/ExpiresNode.php | Compiles expiry tags to CacheControl::setDuration(). |
| src/Support/Html.php | Records CSRF-related storage restrictions. |
| src/Support/Facades/ResponseHeaders.php | Removes obsolete cache-method annotations. |
| src/Support/Facades/CacheControl.php | Exposes the request-scoped cache policy facade. |
| src/Route/RouteServiceProvider.php | Registers middleware and its execution priority. |
| src/Image/ImageTransformer.php | Records pending-transform storage restrictions. |
| src/Http/ResponseHeaders.php | Removes cache state and methods; retains arbitrary headers. |
| src/Http/Middleware/SetHeaders.php | Removes application of accumulated cache settings. |
| src/Http/Middleware/ApplyCacheControl.php | Applies policy, collects dependencies, and dispatches the checkpoint event. |
| src/Http/Events/CacheControlApplied.php | Defines the integration event and snapshot contract. |
| src/Http/CacheControl.php | Collects directives, reasons, and caller attribution. |
| src/Blade/Directives/ResponseDirective.php | Migrates Blade expiry to the new service. |
| composer.lock | Updates the manifest content hash. |
| composer.json | Registers the CacheControl facade alias. |
| CHANGELOG.md | Documents the new API and removed methods. |
| CHANGELOG-WIP.md | Documents HTTP policy and template-expiry changes. |
Review effort: Balanced
Description
Give cache integrations a common source of cache directives, dependency tags, and explanations, rather than making each integration infer intent from response headers.
Core API
CacheControlservice and facade collect request-scoped browser/shared directives using Symfony's cache-control vocabulary, with optional reasons and caller attribution.ApplyCacheControlmiddleware applies those directives on Craft site requests, preserves restrictions, and caps supplied freshness by dependency expiry. Core supplies no default lifetime.CacheControlAppliedevent gives synchronous consumers the actual response, a detached Symfony Response policy snapshot, raw tags, and reasons at the middleware checkpoint. Outer middleware and later listeners can still change the response.Existing API changes
ResponseHeaders::setCache()andnoCache();add()remains.ExpiresandPragmaheaders.