Developers
Cache
The cache holds expensive results — rendered wiki text, a tag cloud, a statistics query — so the next request does not have to compute them again. It is a plain key/value store with a time to live, and nothing in the CMS depends on a value being there.
Reach for it when a value is expensive to compute, the same for everybody, and tolerable when stale. All three. An instrument-booking component might cache the list of instruments and their opening hours, which changes twice a year; it must not cache the day's free slots, which change as members book them, and it must not cache anything that depends on who is looking.
What the facade resolves to
Two keys are registered, and they are not the same object:
public function register()
{
$this->app['cache'] = function($app)
{
return new Manager($app);
};
$this->app['cache.store'] = function($app)
{
$handler = !$app['config']->get('caching') ? 'none' : $app['config']->get('cache_handler');
if ($app->isAdmin())
{
$handler = 'none';
}
return $app['cache']->storage($handler);
};
}
cache is the Hubzero\Cache\Manager,
which resolves and caches storage instances. cache.store is one storage
instance, chosen from the hub's configuration. The Cache facade resolves
cache.store — so a call on the facade lands on a
StorageInterface
implementation, not on the manager.
Note the two switches in the closure. With caching off in
app/config/cache.php the handler is forced to none, and in the
administrator it is forced to none unconditionally. Both None stores
accept every write and return null from every read, so code that caches
still runs; it just never gets a hit.
Storing and reading
use Cache;
// 15 is minutes, not seconds
Cache::put('wiki.r' . $revision->get('id'), $rendered, 15);
$rendered = Cache::get('wiki.r' . $revision->get('id'));
The third argument catches people out. Cache::put($key, $value, 3600)
means two and a half days, not an hour.
That is the shape of nearly every use in the tree — write with a TTL, read back, recompute on a miss:
if (intval($this->book->config('cache', 1)))
{
// Caching
if (!($rendered = Cache::get('wiki.r' . $revision->get('id'))))
{
$rendered = $revision->content($this->page);
Cache::put('wiki.r' . $revision->get('id'), $rendered, intval($this->book->config('cache_time', 15)));
}
$revision->set('pagehtml', $rendered);
}
| Method | What it does |
|---|---|
get($key) |
The value, or null on a miss or an expired entry |
has($key) |
Whether a live entry exists |
put($key, $value, $minutes) |
Store, replacing anything already there |
add($key, $value, $minutes) |
Store only if has() is false; returns false otherwise |
forever($key, $value) |
put() with an expiry far in the future |
forget($key) |
Remove one entry |
clean($group = null) |
Remove one group, or everything |
gc($group = null) |
Remove entries that have expired |
all() |
A per-group summary of what is stored |
Values are serialized, so anything serialize() can round-trip is a legal
value. Store the rendered string, not the model that produced it: a model
carries a database connection and a query object, and what comes back out of
the cache is a half-woken object that fails the first time something calls a
method on it.
Groups
The key is dotted, and the first segment is the group. The file store
turns the group into a directory under app/cache/<client>/ and hashes the
rest of the key into the filename. That is what makes selective clearing
work:
// everything the wiki cached
Cache::clean('wiki');
// the whole cache
Cache::clean();
Components use their own name or a short label for the group — wiki,
tags, groups, members, com_templates, _system. Pick one and prefix
every key with it, or your entries end up in the root of the cache
directory where only a full clean() reaches them.
all() returns one Auditor
per group, carrying group, count and size (in kilobytes). The
administrator's cache screen is built from it.
Drivers
The driver comes from cache_handler in app/config/cache.php. The classes
live in core/libraries/Hubzero/Cache/Storage/:
File (the default), Memcache, Memcached, Apc, WinCache, XCache,
Memory (per-request only) and None. Each has a static isAvailable(),
and Hubzero\Cache\Manager::getStores() returns the lowercased names of the
ones this server can actually use.
To add one, implement StorageInterface and register a resolver on the
manager:
App::get('cache')->extend('example', function($config)
{
return new ExampleStore($config);
});
The name matches a cache_handler value; the closure receives the merged
configuration array, which always carries hash and cachebase.
Rewritten and checked against 2.4-main @ 348f0057c2 on 2026-09-10.