Skip to content

feat(page-cache): full-page HTTP cache with file driver, tag invalidation, and entity bridge#58

Open
michalbiarda wants to merge 4 commits into
marko-php:developfrom
michalbiarda:feature/page-cache-package
Open

feat(page-cache): full-page HTTP cache with file driver, tag invalidation, and entity bridge#58
michalbiarda wants to merge 4 commits into
marko-php:developfrom
michalbiarda:feature/page-cache-package

Conversation

@michalbiarda
Copy link
Copy Markdown

Summary

Introduces three new packages for full-page HTTP response caching:

  • marko/page-cache — interface package with PageCacheInterface, #[Cacheable(ttl, tags, provider)] attribute, PageCacheMiddleware (registered globally), CacheabilityChecker, CLI commands (page-cache:clear, page-cache:purge, page-cache:status), CacheTagProviderInterface for dynamic per-request tags, IdentityInterface for entity-driven invalidation, and a boot-time IdentityBridgeValidator that fails loudly when the bridge is missing
  • marko/page-cache-file — file driver implementing PageCacheInterface with atomic writes and tag reverse-index for purgeTag()
  • marko/page-cache-entity — bridge package: three auto-discovered observers (PurgeOnEntityCreated/Updated/Deleted) delegate to IdentityPurger, which purges all tags returned by entities implementing IdentityInterface when saved or deleted

Test plan

  • composer test passes
  • ./vendor/bin/phpcs && ./vendor/bin/php-cs-fixer fix passes with no changes
  • Routes with #[Cacheable] are served from cache on second request
  • page-cache:purge <url> and page-cache:purge --tag <tag> clear the correct entries
  • #[Cacheable(provider: SomeProvider::class)] merges dynamic tags with static tags
  • Saving an entity implementing IdentityInterface purges its tags from the page cache
  • Boot throws PageCacheException::missingEntityBridge() when IdentityInterface is implemented without the bridge installed

🤖 Generated with Claude Code

michalbiarda and others added 4 commits May 9, 2026 20:31
…ages

Introduces full-page HTTP response caching with attribute-driven opt-in,
tag-based invalidation, and a global middleware that intercepts requests
to serve or store cached responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move helper functions from Pest.php into helpers.php (package-scoped
  require_once) so they load correctly under the root phpunit.xml runner
- Rename createDriver/cleanupDir to createPageCacheFileDriver/cleanupPageCacheDir
  to avoid global function collisions with cache-redis and database tests
- Rename makeRequest/makeResponse to makeCacheCheckerRequest/makeCacheCheckerResponse
  in CacheabilityCheckerTest to avoid collision with layout package tests
- Fix PackageStructureTest dirname depth (2→3) for root composer.json lookup
- Add missing .gitattributes, LICENSE to page-cache and page-cache-file packages
- Add page-cache and page-cache-file to GitHub issue templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…event public/ exposure

FilePageCacheDriver now injects ProjectPaths and resolves relative paths
against the project base directory, matching the DebugbarStorage pattern.
This prevents cache files from landing in public/ when PHP's CWD is set
to the web root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…age-cache-entity bridge

- CacheTagProviderInterface + provider param on #[Cacheable] for per-request dynamic tags
- IdentityInterface in marko/page-cache for entities to declare their cache identities
- PageCacheMiddleware resolves provider via container, merges static + dynamic tags (deduplicated)
- marko/page-cache-entity bridge package: IdentityPurger + three observers (Created/Updated/Deleted)
- IdentityBridgeValidator: loud-fail boot check when IdentityInterface is used without the bridge installed
- README and docs updates for all new extension points

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the enhancement New feature or request label May 11, 2026
@michalbiarda
Copy link
Copy Markdown
Author

@markshust The whole feature was implemented using your Claude Code automation. When you decide to merge it, I'll work on implementing more drivers (Varnish, etc.). File driver was a proof of concept.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant