Caching#
Hot Tips
- Caching is off by default: flip one
.envsetting to enable it - Built on PhpFastCache using the filesystem driver
- ORM queries, route responses, and Twig templates are all cached automatically once enabled
- Use
@no-cache/@cacheannotations to override caching per route
Overview#
Tina4 ships with a caching layer powered by PhpFastCache. When enabled, three things happen automatically:
- ORM query results are cached so repeated
load()/select()calls skip the database. - Route responses are stored and served from cache on subsequent requests.
- Twig templates are compiled once and reused from the
./cachedirectory.
The cache files live in a cache/ folder at the root of your project.
Enabling caching#
Open (or create) the .env file in your project root and set:
[Project Settings]TINA4_CACHE_BACKEND=trueWhen the application boots it reads this value. If TINA4_CACHE_BACKEND is true, Tina4 creates a PhpFastCache files instance pointed at {TINA4_PUBLIC_DIR}/cache.
To turn caching off again, set the value back to false, no code changes required.
Manual caching with Cache::set() and Cache::get()#
The \Tina4\Cache class gives you direct access to the cache store.
Storing a value#
$cache = new \Tina4\Cache();// Cache a string for 120 seconds$cache->set("my-key", "hello world", 120);// Cache an array for the default 60 seconds$cache->set("user-list", $users);Signature:
public function set(string $keyName, mixed $value, int $expires = 60): boolReturns true on success, false if the cache backend is not available.
Retrieving a value#
$cache = new \Tina4\Cache();$value = $cache->get("my-key");if ($value === null) { // cache miss - fetch from the source}Signature:
public function get(string $keyName): mixedReturns the cached data, or null on a miss.
Practical example#
\Tina4\Get::add("/api/products", function (\Tina4\Response $response) { $cache = new \Tina4\Cache(); $products = $cache->get("all-products"); if ($products === null) { global $DBA; $products = $DBA->fetch("select * from product")->asArray(); $cache->set("all-products", $products, 300); // cache for 5 minutes } return $response($products, HTTP_OK, APPLICATION_JSON);});ORM query caching#
The \Tina4\ORMCache class is used internally by the ORM. When TINA4_CACHE_BACKEND is true:
- Every
load()call checks the cache first using a key derived from the SQL:
"orm" . md5($sqlStatement)
- On a cache hit the database is skipped entirely.
- On a cache miss the query runs and the result is stored for 60 seconds.
- Any
save()invalidates the relevant cache entry by setting it tonull.
When TINA4_CACHE_BACKEND is false, ORMCache::get() always returns null and ORMCache::set() returns true, so the ORM falls through to the database every time.
You do not need to interact with ORMCache directly, the ORM handles it automatically.
Route response caching#
When caching is enabled, the Router caches the full response (content, HTTP code, headers, content type) for every matched route.
How it works#
- A request comes in and the Router looks for a cached response using the key:
"url_" . md5($url . $method)
- If a cached entry exists it is returned immediately, the route callback is never executed.
- If there is no cache entry, the route runs normally and the response is cached for 360 seconds (6 minutes).
Per-route control with annotations#
You can override the global setting on individual routes using doc-block annotations:
/** * This route is always cached, even if TINA4_CACHE_BACKEND is false * @cache */\Tina4\Get::add("/api/cached-data", function (\Tina4\Response $response) { return $response(["data" => "this will be cached"]);});/** * This route is never cached, even if TINA4_CACHE_BACKEND is true * @no-cache */\Tina4\Get::add("/api/live-data", function (\Tina4\Response $response) { return $response(["timestamp" => time()]);});Debug mode bypass#
When TINA4_DEBUG is true, .twig files and anything under /public/ are not served from cache. This lets you iterate on templates without clearing cache constantly.
Twig template caching#
When TINA4_CACHE_BACKEND is true, the Twig environment is created with compiled template caching:
// Internally Tina4 does:$twig = new Environment($twigLoader, ["debug" => TINA4_DEBUG, "cache" => "./cache"]);Compiled templates are stored in ./cache and reused until the source .twig file changes or the cache is cleared.
When caching is off, Twig recompiles templates on every request.
Clearing the cache#
Tina4 exposes a built-in route to wipe the cache directory:
GET /cache/clearThis deletes everything inside ./cache and returns "OK".
You can also clear it manually:
rm -rf ./cache/*Cache key patterns#
| Layer | Key format | Default TTL |
|---|---|---|
| Manual | Any string you choose | 60 seconds |
| ORM queries | "orm" . md5($sql) | 60 seconds |
| Route responses | "url_" . md5($url . $method) | 360 seconds |
| Twig templates | Managed by Twig (filesystem) | Until source changes |
Configuration via .env#
The full set of cache-related settings in your .env:
[Project Settings]TINA4_CACHE_BACKEND=true # Enable or disable all caching (default: false)TINA4_DEBUG=false # When true, Twig/public file caching is bypassedThe cache backend is always the filesystem driver pointed at {TINA4_PUBLIC_DIR}/cache. No additional configuration (Redis, Memcached, etc.) is needed.