feat(page-cache): full-page HTTP cache with file driver, tag invalidation, and entity bridge#58
Conversation
…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>
|
@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. |
Maintainer follow-up to PR marko-php#58. All changes are mechanical / non-behavioural: 1. **Slim READMEs to match Marko convention.** Per `docs/DOCS-STANDARDS.md`, package READMEs are slim pointers (Title + one-liner, Installation, Quick Example, Documentation link) and the docs site is the source of truth. Sibling packages (`cache`, `cache-file`, `database`) already follow this format. 2. **Remove vestigial README-content assertions.** Deleted `packages/page-cache/tests/ReadmeTest.php` and dropped two tests in `page-cache-entity/tests/PackageStructureTest.php` that asserted the README contained `IdentityPurger` signatures, observer class names, and `## API Reference`. Replaced with a docs-link assertion. Sibling slim packages do not assert README content. 3. **Fix incorrect FQCN namespaces in docs pages.** `Marko\PageCache\Service\CacheabilityChecker` → `Marko\PageCache\CacheabilityChecker` `Marko\PageCache\ValueObjects\CachePolicy` → `Marko\PageCache\CachePolicy` `Marko\PageCache\ValueObjects\CacheKey` → `Marko\PageCache\CacheKey` Affects `page-cache.md` (4 occurrences) and `page-cache-file.md` (1). Copy-pasting the docs page examples now matches the real namespaces. 4. **Lint cleanup (`phpcbf` + `php-cs-fixer`).** Resolved all 53 sniff violations across 17 files in the three new packages — multiline method signatures, multiline function calls, and php-cs-fixer normalization. No semantic changes. Verified: `composer test` passes (5038 / 0 failed), `phpcs` and `php-cs-fixer` both clean. Co-Authored-By: Michał Biarda <1135380+michalbiarda@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Hi Michał — thanks for the page-cache packages, this is a really nice addition. I've pushed a maintainer follow-up commit ( 1. Slim READMEs. Marko's docs convention (see 2. Vestigial README-content tests. 3. Docs-page namespace bugs. A few
A user copy-pasting from the docs would have hit class-not-found errors. Fixed in both 4. Lint. 53 Also flagging one architectural observation, not addressed here: Verified locally: |
|
Cool. Thanks for the fixes and reasoning behind them. I'm happy to have my first PR merged to Marko 😄. Now it's time to implement other drivers 👿. |
Summary
Introduces three new packages for full-page HTTP response caching:
marko/page-cache— interface package withPageCacheInterface,#[Cacheable(ttl, tags, provider)]attribute,PageCacheMiddleware(registered globally),CacheabilityChecker, CLI commands (page-cache:clear,page-cache:purge,page-cache:status),CacheTagProviderInterfacefor dynamic per-request tags,IdentityInterfacefor entity-driven invalidation, and a boot-timeIdentityBridgeValidatorthat fails loudly when the bridge is missingmarko/page-cache-file— file driver implementingPageCacheInterfacewith atomic writes and tag reverse-index forpurgeTag()marko/page-cache-entity— bridge package: three auto-discovered observers (PurgeOnEntityCreated/Updated/Deleted) delegate toIdentityPurger, which purges all tags returned by entities implementingIdentityInterfacewhen saved or deletedTest plan
composer testpasses./vendor/bin/phpcs && ./vendor/bin/php-cs-fixer fixpasses with no changes#[Cacheable]are served from cache on second requestpage-cache:purge <url>andpage-cache:purge --tag <tag>clear the correct entries#[Cacheable(provider: SomeProvider::class)]merges dynamic tags with static tagsIdentityInterfacepurges its tags from the page cachePageCacheException::missingEntityBridge()whenIdentityInterfaceis implemented without the bridge installed🤖 Generated with Claude Code