Caching

  • class Cake\Cache\Cache

Caching can be used to make reading from expensive or slow resources faster, bymaintaining a second copy of the required data in a faster or closer storagesystem. For example, you can store the results of expensive queries, or remotewebservice access that doesn’t frequently change in a cache. Once in the cache,reading data from the cache is much cheaper than accessing the remote resource.

Caching in CakePHP is facilitated by the Cache class.This class provides a static interface and uniform API tointeract with various Caching implementations. CakePHPprovides several cache engines, and provides a simple interface if you need tobuild your own backend. The built-in caching engines are:

  • File File cache is a simple cache that uses local files. Itis the slowest cache engine, and doesn’t provide as many features foratomic operations. However, since disk storage is often quite cheap,storing large objects, or elements that are infrequently writtenwork well in files.
  • Memcached Uses the Memcachedextension.
  • Redis Uses the phpredisextension. Redis provides a fast and persistent cache system similar toMemcached, also provides atomic operations.
  • Apcu APCu cache uses the PHP APCu extension.This extension uses shared memory on the webserver to store objects.This makes it very fast, and able to provide atomic read/write features.
  • Wincache Wincache uses the Wincacheextension. Wincache is similar to APC in features and performance, butoptimized for Windows and IIS.
  • Array Stores all data in an array. This engine does not providepersistent storage and is intended for use in application test suites.
  • Null The null engine doesn’t actually store anything and fails all readoperations.

Regardless of the CacheEngine you choose to use, your application interacts withCake\Cache\Cache.

Configuring Cache Engines

  • static Cake\Cache\Cache::setConfig($key, $config = null)

Your application can configure any number of ‘engines’ during its bootstrapprocess. Cache engine configurations are defined in config/app.php.

For optimal performance CakePHP requires two cache engines to be defined.

  • cake_core is used for storing file maps, and parsed results ofInternationalization & Localization files.
  • cake_model, is used to store schema descriptions for your applicationsmodels.

Using multiple engine configurations also lets you incrementally change thestorage as needed. For example in your config/app.php you could put thefollowing:

  1. // ...
  2. 'Cache' => [
  3. 'short' => [
  4. 'className' => 'File',
  5. 'duration' => '+1 hours',
  6. 'path' => CACHE,
  7. 'prefix' => 'cake_short_'
  8. ],
  9. // Using a fully namespaced name.
  10. 'long' => [
  11. 'className' => 'Cake\Cache\Engine\FileEngine',
  12. 'duration' => '+1 week',
  13. 'probability' => 100,
  14. 'path' => CACHE . 'long' . DS,
  15. ]
  16. ]
  17. // ...

Configuration options can also be provided as a DSN string. This isuseful when working with environment variables or PaaS providers:

  1. Cache::setConfig('short', [
  2. 'url' => 'memcached://user:password@cache-host/?timeout=3600&prefix=myapp_',
  3. ]);

When using a DSN string you can define any additional parameters/options asquery string arguments.

You can also configure Cache engines at runtime:

  1. // Using a short name
  2. Cache::setConfig('short', [
  3. 'className' => 'File',
  4. 'duration' => '+1 hours',
  5. 'path' => CACHE,
  6. 'prefix' => 'cake_short_'
  7. ]);
  8.  
  9. // Using a fully namespaced name.
  10. Cache::setConfig('long', [
  11. 'className' => 'Cake\Cache\Engine\FileEngine',
  12. 'duration' => '+1 week',
  13. 'probability' => 100,
  14. 'path' => CACHE . 'long' . DS,
  15. ]);
  16.  
  17. // Using a constructed object.
  18. $object = new FileEngine($config);
  19. Cache::setConfig('other', $object);

The name of these engine configurations (‘short’ and ‘long’) are used as the $configparameter for Cake\Cache\Cache::write() andCake\Cache\Cache::read(). When configuring cache engines you canrefer to the class name using the following syntaxes:

  1. // Short name (in App\ or Cake namespaces)
  2. Cache::setConfig('long', ['className' => 'File']);
  3.  
  4. // Plugin short name
  5. Cache::setConfig('long', ['className' => 'MyPlugin.SuperCache']);
  6.  
  7. // Full namespace
  8. Cache::setConfig('long', ['className' => 'Cake\Cache\Engine\FileEngine']);
  9.  
  10. // An object implementing CacheEngineInterface
  11. Cache::setConfig('long', ['className' => $myCache]);

Note

When using the FileEngine you might need to use the mask option toensure cache files are made with the correct permissions.

Engine Options

Each engine accepts the following options:

  • duration Specify how long items in this cache configuration last.Specified as a strtotime() compatible expression.
  • groups List of groups or ‘tags’ associated to every key stored in thisconfig. Useful when you need to delete a subset of data from a cache.
  • prefix Prepended to all entries. Good for when you need to sharea keyspace with either another cache config or another application.
  • probability Probability of hitting a cache gc cleanup. Setting to 0 will disableCache::gc() from ever being called automatically.

FileEngine Options

FileEngine uses the following engine specific options:

  • isWindows Automatically populated with whether the host is windows or not
  • lock Should files be locked before writing to them?
  • mask The mask used for created files
  • path Path to where cachefiles should be saved. Defaults to system’s temp dir.

RedisEngine Options

RedisEngine uses the following engine specific options:

  • port The port your Redis server is running on.
  • host The host your Redis server is running on.
  • database The database number to use for connection.
  • password Redis server password.
  • persistent Should a persistent connection be made to Redis.
  • timeout Connection timeout for Redis.
  • unix_socket Path to a unix socket for Redist.

MemcacheEngine Options

  • compress Whether to compress data.
  • username Login to access the Memcache server.
  • password Password to access the Memcache server.
  • persistent The name of the persistent connection. All configurations usingthe same persistent value will share a single underlying connection.
  • serialize The serializer engine used to serialize data. Available engines are php,igbinary and json. Beside php, the memcached extension must be compiled with theappropriate serializer support.
  • servers String or array of memcached servers. If an array MemcacheEngine will usethem as a pool.
  • options Additional options for the memcached client. Should be an array of option => value.Use the \Memcached::OPT_* constants as keys.

Configuring Cache Fallbacks

In the event that an engine is not available, such as the FileEngine tryingto write to an unwritable folder or the RedisEngine failing to connect toRedis, the engine will fall back to the noop NullEngine and trigger a loggableerror. This prevents the application from throwing an uncaught exception due tocache failure.

You can configure Cache configurations to fall back to a specified config usingthe fallback configuration key:

  1. Cache::setConfig('redis', [
  2. 'className' => 'Redis',
  3. 'duration' => '+1 hours',
  4. 'prefix' => 'cake_redis_',
  5. 'host' => '127.0.0.1',
  6. 'port' => 6379,
  7. 'fallback' => 'default',
  8. ]);

If the Redis server unexpectedly failed, writing to the redis cacheconfiguration would fall back to writing to the default cache configuration.If writing to the default cache configuration also failed in this scenario, theengine would fall back once again to the NullEngine and prevent the applicationfrom throwing an uncaught exception.

You can turn off cache fallbacks with false:

  1. Cache::setConfig('redis', [
  2. 'className' => 'Redis',
  3. 'duration' => '+1 hours',
  4. 'prefix' => 'cake_redis_',
  5. 'host' => '127.0.0.1',
  6. 'port' => 6379,
  7. 'fallback' => false
  8. ]);

When there is no fallback cache failures will be raised as exceptions.

Removing Configured Cache Engines

  • static Cake\Cache\Cache::drop($key)

Once a configuration is created you cannot change it. Instead you should dropthe configuration and re-create it using Cake\Cache\Cache::drop() andCake\Cache\Cache::setConfig(). Dropping a cache engine will removethe config and destroy the adapter if it was constructed.

Writing to a Cache

  • static Cake\Cache\Cache::write($key, $value, $config = 'default')

Cache::write() will write a $value to the Cache. You can read ordelete this value later by referring to it by $key. You mayspecify an optional configuration to store the cache in as well. Ifno $config is specified, default will be used. Cache::write()can store any type of object and is ideal for storing results ofmodel finds:

  1. if (($posts = Cache::read('posts')) === false) {
  2. $posts = $someService->getAllPosts();
  3. Cache::write('posts', $posts);
  4. }

Using Cache::write() and Cache::read() to reduce the numberof trips made to the database to fetch posts.

Note

If you plan to cache the result of queries made with the CakePHP ORM,it is better to use the built-in cache capabilities of the Query objectas described in the Caching Loaded Results section

Writing Multiple Keys at Once

  • static Cake\Cache\Cache::writeMany($data, $config = 'default')

You may find yourself needing to write multiple cache keys at once. While youcan use multiple calls to write(), writeMany() allows CakePHP to usemore efficient storage API’s where available. For example using writeMany()save multiple network connections when using Memcached:

  1. $result = Cache::writeMany([
  2. 'article-' . $slug => $article,
  3. 'article-' . $slug . '-comments' => $comments
  4. ]);
  5.  
  6. // $result will contain
  7. ['article-first-post' => true, 'article-first-post-comments' => true]

Read Through Caching

  • static Cake\Cache\Cache::remember($key, $callable, $config = 'default')

Cache makes it easy to do read-through caching. If the named cache key exists,it will be returned. If the key does not exist, the callable will be invokedand the results stored in the cache at the provided key.

For example, you often want to cache remote service call results. You could useremember() to make this simple:

  1. class IssueService
  2. {
  3. public function allIssues($repo)
  4. {
  5. return Cache::remember($repo . '-issues', function () use ($repo) {
  6. return $this->fetchAll($repo);
  7. });
  8. }
  9. }

Reading From a Cache

  • static Cake\Cache\Cache::read($key, $config = 'default')

Cache::read() is used to read the cached value stored under$key from the $config. If $config is null the defaultconfig will be used. Cache::read() will return the cached valueif it is a valid cache or false if the cache has expired ordoesn’t exist. The contents of the cache might evaluate false, somake sure you use the strict comparison operators: === or!==.

For example:

  1. $cloud = Cache::read('cloud');
  2. if ($cloud !== false) {
  3. return $cloud;
  4. }
  5.  
  6. // Generate cloud data
  7. // ...
  8.  
  9. // Store data in cache
  10. Cache::write('cloud', $cloud);
  11.  
  12. return $cloud;

Or if you are using another cache configuration called short, you canspecify it in Cache::read() and Cache::write() calls as below:

  1. // Read key "cloud", but from short configuration instead of default
  2. $cloud = Cache::read('cloud', 'short');
  3. if ($cloud !== false) {
  4. return $cloud;
  5. }
  6.  
  7. // Generate cloud data
  8. // ...
  9.  
  10. // Store data in cache, using short cache configuration instead of default
  11. Cache::write('cloud', $cloud, 'short');
  12.  
  13. return $cloud;

Reading Multiple Keys at Once

  • static Cake\Cache\Cache::readMany($keys, $config = 'default')

After you’ve written multiple keys at once, you’ll probably want to read them aswell. While you could use multiple calls to read(), readMany() allowsCakePHP to use more efficient storage API’s where available. For example usingreadMany() save multiple network connections when using Memcached:

  1. $result = Cache::readMany([
  2. 'article-' . $slug,
  3. 'article-' . $slug . '-comments'
  4. ]);
  5. // $result will contain
  6. ['article-first-post' => '...', 'article-first-post-comments' => '...']

Deleting From a Cache

  • static Cake\Cache\Cache::delete($key, $config = 'default')

Cache::delete() will allow you to completely remove a cachedobject from the store:

  1. // Remove a key
  2. Cache::delete('my_key');

Deleting Multiple Keys at Once

  • static Cake\Cache\Cache::deleteMany($keys, $config = 'default')

After you’ve written multiple keys at once, you may want to delete them. Whileyou could use multiple calls to delete(), deleteMany() allows CakePHP to usemore efficient storage API’s where available. For example using deleteMany()save multiple network connections when using Memcached:

  1. $result = Cache::deleteMany([
  2. 'article-' . $slug,
  3. 'article-' . $slug . '-comments'
  4. ]);
  5. // $result will contain
  6. ['article-first-post' => true, 'article-first-post-comments' => true]

Clearing Cached Data

  • static Cake\Cache\Cache::clear($check, $config = 'default')

Destroy all cached values for a cache configuration. In engines like: Apcu,Memcached, and Wincache, the cache configuration’s prefix is used to removecache entries. Make sure that different cache configurations have differentprefixes:

  1. // Will only clear expired keys.
  2. Cache::clear(true);
  3.  
  4. // Will clear all keys.
  5. Cache::clear(false);

Note

Because APCu and Wincache use isolated caches for webserver and CLI theyhave to be cleared separately (CLI cannot clear webserver and vice versa).

Using Cache to Store Counters

  • static Cake\Cache\Cache::increment($key, $offset = 1, $config = 'default')
  • static Cake\Cache\Cache::decrement($key, $offset = 1, $config = 'default')

Counters in your application are good candidates for storage in a cache. As anexample, a simple countdown for remaining ‘slots’ in a contest could be storedin Cache. The Cache class exposes atomic ways to increment/decrement countervalues in an easy way. Atomic operations are important for these values as itreduces the risk of contention, and ability for two users to simultaneouslylower the value by one, resulting in an incorrect value.

After setting an integer value you can manipulate it using increment() anddecrement():

  1. Cache::write('initial_count', 10);
  2.  
  3. // Later on
  4. Cache::decrement('initial_count');
  5.  
  6. // Or
  7. Cache::increment('initial_count');

Note

Incrementing and decrementing do not work with FileEngine. You should useAPCu, Wincache, Redis or Memcached instead.

Using Cache to Store Common Query Results

You can greatly improve the performance of your application by putting resultsthat infrequently change, or that are subject to heavy reads into the cache.A perfect example of this are the results fromCake\ORM\Table::find(). The Query object allows you to cacheresults using the cache() method. See the Caching Loaded Results sectionfor more information.

Using Groups

Sometimes you will want to mark multiple cache entries to belong to certaingroup or namespace. This is a common requirement for mass-invalidating keyswhenever some information changes that is shared among all entries in the samegroup. This is possible by declaring the groups in cache configuration:

  1. Cache::setConfig('site_home', [
  2. 'className' => 'Redis',
  3. 'duration' => '+999 days',
  4. 'groups' => ['comment', 'article']
  5. ]);
  • Cake\Cache\Cache::clearGroup($group, $config = 'default')

Let’s say you want to store the HTML generated for your homepage in cache, butwould also want to automatically invalidate this cache every time a comment orpost is added to your database. By adding the groups comment and article,we have effectively tagged any key stored into this cache configuration withboth group names.

For instance, whenever a new post is added, we could tell the Cache engine toremove all entries associated to the article group:

  1. // src/Model/Table/ArticlesTable.php
  2. public function afterSave($event, $entity, $options = [])
  3. {
  4. if ($entity->isNew()) {
  5. Cache::clearGroup('article', 'site_home');
  6. }
  7. }
  • static Cake\Cache\Cache::groupConfigs($group = null)

groupConfigs() can be used to retrieve mapping between group andconfigurations, i.e.: having the same group:

  1. // src/Model/Table/ArticlesTable.php
  2.  
  3. /**
  4. * A variation of previous example that clears all Cache configurations
  5. * having the same group
  6. */
  7. public function afterSave($event, $entity, $options = [])
  8. {
  9. if ($entity->isNew()) {
  10. $configs = Cache::groupConfigs('article');
  11. foreach ($configs['article'] as $config) {
  12. Cache::clearGroup('article', $config);
  13. }
  14. }
  15. }

Groups are shared across all cache configs using the same engine and sameprefix. If you are using groups and want to take advantage of group deletion,choose a common prefix for all your configs.

Globally Enable or Disable Cache

  • static Cake\Cache\Cache::disable

You may need to disable all Cache read & writes when trying to figure out cacheexpiration related issues. You can do this using enable() anddisable():

  1. // Disable all cache reads, and cache writes.
  2. Cache::disable();

Once disabled, all reads and writes will return null.

  • static Cake\Cache\Cache::enable

Once disabled, you can use enable() to re-enable caching:

  1. // Re-enable all cache reads, and cache writes.
  2. Cache::enable();
  • static Cake\Cache\Cache::enabled

If you need to check on the state of Cache, you can use enabled().

Creating a Cache Engine

You can provide custom Cache engines in App\Cache\Engine as wellas in plugins using $plugin\Cache\Engine. Cache engines must be in a cachedirectory. If you had a cache engine named MyCustomCacheEngineit would be placed in either src/Cache/Engine/MyCustomCacheEngine.php.Or in plugins/MyPlugin/src/Cache/Engine/MyCustomCacheEngine.php aspart of a plugin. Cache configs from plugins need to use the plugindot syntax:

  1. Cache::setConfig('custom', [
  2. 'className' => 'MyPlugin.MyCustomCache',
  3. // ...
  4. ]);

Custom Cache engines must extend Cake\Cache\CacheEngine whichdefines a number of abstract methods as well as provides a few initializationmethods.

The required API for a CacheEngine is

  • class Cake\Cache\CacheEngine
  • The base class for all cache engines used with Cache.
  • Cake\Cache\CacheEngine::write($key, $value)

Returns:boolean for success.

Write value for a key into cache, Return trueif the data was successfully cached, false on failure.

  • Cake\Cache\CacheEngine::read($key)

Returns:The cached value or false for failure.

Read a key from the cache. Return false to indicatethe entry has expired or does not exist.

  • Cake\Cache\CacheEngine::delete($key)

Returns:Boolean true on success.

Delete a key from the cache. Return false to indicate thatthe entry did not exist or could not be deleted.

  • Cake\Cache\CacheEngine::clear($check)

Returns:Boolean true on success.

Delete all keys from the cache. If $check is true, you shouldvalidate that each value is actually expired.

  • Cake\Cache\CacheEngine::clearGroup($group)

Returns:Boolean true on success.

Delete all keys from the cache belonging to the same group.

  • Cake\Cache\CacheEngine::decrement($key, $offset = 1)

Returns:Boolean true on success.

Decrement a number under the key and return decremented value

  • Cake\Cache\CacheEngine::increment($key, $offset = 1)

Returns:Boolean true on success.

Increment a number under the key and return incremented value