v0.35.0
2 November 2026
A view can now keep its full-page render for anonymous visitors, and caches follow the query a render read.
Added
- A view's
cachein_index.jsonkeeps the full-page render of its pages for anonymous visitors:"cache": 300or{"ttl": 300, "scope": "page"}.scopesite(the default) is cleared by any write,pageonly by a write to the page, above it or below it. Kept pages are sent withCache-Control: no-cacheand anETag, and answer304to a matchingIf-None-Match. - A render is not kept when it reads the session, sets a cookie or an
hx-header, or is not a200. Inline{cache}regions shorten the page's life to their own. Cache::getVaried()andCache::setVaried()key an entry on the query parameters the render read throughRequest::query().Request::queryKeys()lists them.Cache::flushTree($url)empties the caches of a page, every page above it and everything below it.- A
Cacherejects aset()from a render that began before a flush, so a save is never overtaken by a stale render. "cache": falsein config turns every cache off: the stores, kept pages and the headers that let a browser keep a response.- Events
page.cache:hit,page.cache:skip,cache.get:after,cache.set:afterandcache.flush:after, and a Clockwork Cache panel that shows them. $app->users('role=admin,sort=-created')takes a find query.Res::status(),Res::headerNames(),Ses::reads()andApp::cacheDisabled().Referencetakes an optionalCacheand keeps the reflected API entries in it.- Served page files answer
If-Modified-Sincewith304, and a request carrying the file's current mtime token isimmutable.
Changed
- A view's
cacheis seconds, not aCache-Controlstring. Write"cache": 300where it was"public, max-age=300". A kept page skips the router and controllers, so opt in only views whose GET handling has no side effects. debugno longer turns the caches off. Set"cache": falsewhile editing templates.- A write to a page clears the caches of every page below it as well as those above.
- The fragment and
{cache}keys no longer include the whole query string. Code that reads$_GETdirectly is not seen: read it throughRequest::query(). - The
Cachetable is rebuilt on first use (schema 2), so existing entries are dropped. SessionRoot::user()checks the session cookie once per request.
Removed
phlat/Dockerfile,phlat/Dockerfile.dist,phlat/Caddyfileand.dockerignore: the FrankenPHP image and the reusablephlat/pageimage are gone. The PHP-FPM setup (phlat/Dockerfile.fpm,phlat/Caddyfile.fpm) remains.- The
docker:publish,docker:publish-devandserver:*tasks inphlat/taskfile.yml.