diff --git a/cache/Cache.php b/cache/Cache.php
index b953523b9..acf8621a3 100644
--- a/cache/Cache.php
+++ b/cache/Cache.php
@@ -1,109 +1,10 @@
Using a cache
- *
- *
- * // foo is any name (try to be specific), and is used to get configuration
- * // & storage info
- * $cache = SS_Cache::factory('foo');
- *
- * if (!($result = $cache->load($cachekey))) {
- * $result = caluate some how;
- * $cache->save($result);
- * }
- *
- * return $result;
- *
*
- * Normally there's no need to remove things from the cache - the cache
- * backends clear out entries based on age & maximum allocated storage. If you
- * include the version of the object in the cache key, even object changes
- * don't need any invalidation.
- *
- *
- * // _config.php
- * if (Director::isDev()) {
- * SS_Cache::set_cache_lifetime('any', -1, 100);
- * //
- *
- *
- *
- * // _config.php
- * SS_Cache::add_backend(
- * 'primary_memcached',
- * 'Memcached',
- * array(
- * 'host' => 'localhost',
- * 'port' => 11211,
- * 'persistent' => true,
- * 'weight' => 1,
- * 'timeout' => 5,
- * 'retry_interval' => 15,
- * 'status' => true,
- * 'failure_callback' => ''
- * )
- * );
- *
- * SS_Cache::pick_backend('primary_memcached', 'any', 10);
- *
- * // Aggregate needs a backend with tag support, which memcached doesn't
- * // provide
- * SS_Cache::pick_backend('default', 'aggregate', 20);
- *
- *
- *
- * SS_Cache::add_backend('two-level', 'Two-Levels', array(
- * 'slow_backend' => 'File',
- * 'fast_backend' => 'Apc',
- * 'slow_backend_options' => array(
- * 'cache_dir' => TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache'
- * )
- * ));
- *
- * // No need for special backend for aggregate - TwoLevels with a File slow
- * // backend supports tags
- * SS_Cache::pick_backend('two-level', 'Two-Levels', 10);
- *
- *
- *
- * $cache = SS_Cache::factory('foo');
- * $cache->remove($cachekey);
- *
- *
- *
- * $cache = SS_Cache::factory('foo');
- * $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
- *
+ * @see http://doc.silverstripe.org/framework/en/topics/caching
*
* @package framework
* @subpackage core
diff --git a/docs/en/topics/caching.md b/docs/en/topics/caching.md
index 61a6a4225..26c8d55e4 100644
--- a/docs/en/topics/caching.md
+++ b/docs/en/topics/caching.md
@@ -21,6 +21,127 @@ executing the action is limited to the following cases when performed via a web
* A user is logged in with ADMIN permissions
* An error occurs during startup
-## Custom Caches
+## The Cache API
-See `[api:SS_Cache]`.
\ No newline at end of file
+The `[api:SS_Cache]` class provides a bunch of static functions wrapping the Zend_Cache system
+in something a little more easy to use with the SilverStripe config system.
+
+A `Zend_Cache` has both a frontend (determines how to get the value to cache,
+and how to serialize it for storage) and a backend (handles the actual
+storage).
+
+Rather than require library code to specify the backend directly, cache
+consumers provide a name for the cache backend they want. The end developer
+can then specify which backend to use for each name in their project's
+configuration. They can also use 'all' to provide a backend for all named
+caches.
+
+End developers provide a set of named backends, then pick the specific
+backend for each named cache. There is a default File cache set up as the
+'default' named backend, which is assigned to 'all' named caches.
+
+## Using Caches
+
+Caches can be created and retrieved through the `SS_Cache::factory()` method.
+The returned object is of type `Zend_Cache`.
+
+ :::php
+ // foo is any name (try to be specific), and is used to get configuration
+ // & storage info
+ $cache = SS_Cache::factory('foo');
+ if (!($result = $cache->load($cachekey))) {
+ $result = caluate some how;
+ $cache->save($result);
+ }
+ return $result;
+
+Normally there's no need to remove things from the cache - the cache
+backends clear out entries based on age and maximum allocated storage. If you
+include the version of the object in the cache key, even object changes
+don't need any invalidation. You can force disable the cache though,
+e.g. in development mode.
+
+ :::php
+ // Disables all caches
+ SS_Cache::set_cache_lifetime('any', -1, 100);
+
+You can also specifically clean a cache.
+Keep in mind that `Zend_Cache::CLEANING_MODE_ALL` deletes all cache
+entries across all caches, not just for the 'foo' cache in the example below.
+
+ :::php
+ $cache = SS_Cache::factory('foo');
+ $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
+
+A single element can be invalidated through its cache key.
+
+ :::php
+ $cache = SS_Cache::factory('foo');
+ $cache->remove($cachekey);
+
+In order to increase the chance of your cache actually being hit,
+it often pays to increase the lifetime of caches ("TTL").
+It defaults to 10 minutes (600s) in SilverStripe, which can be
+quite short depending on how often your data changes.
+Keep in mind that data expiry should primarily be handled by your cache key,
+e.g. by including the `LastEdited` value when caching `DataObject` results.
+
+ :::php
+ // set all caches to 3 hours
+ SS_Cache::set_cache_lifetime('any', 60*60*3);
+
+## Alternative Cache Backends
+
+By default, SilverStripe uses a file-based caching backend.
+Together with a file stat cache like [APC](http://us2.php.net/manual/en/book.apc.php)
+this is reasonably quick, but still requires access to slow disk I/O.
+The `Zend_Cache` API supports various caching backends ([list](http://framework.zend.com/manual/1.12/en/zend.cache.backends.html))
+which can provide better performance, including APC, Xcache, ZendServer, Memcached and SQLite.
+
+### Memcached
+
+This backends stores cache records into a [memcached](http://www.danga.com/memcached/)
+server. memcached is a high-performance, distributed memory object caching system.
+To use this backend, you need a memcached daemon and the memcache PECL extension.
+
+ :::php
+ // _config.php
+ SS_Cache::add_backend(
+ 'primary_memcached',
+ 'Memcached',
+ array(
+ 'host' => 'localhost',
+ 'port' => 11211,
+ 'persistent' => true,
+ 'weight' => 1,
+ 'timeout' => 5,
+ 'retry_interval' => 15,
+ 'status' => true,
+ 'failure_callback' => ''
+ )
+ );
+ SS_Cache::pick_backend('primary_memcached', 'any', 10);
+
+### APC
+
+This backends stores cache records in shared memory through the [APC](http://pecl.php.net/package/APC)
+ (Alternative PHP Cache) extension (which is of course need for using this backend).
+
+ :::php
+ SS_Cache::add_backend('primary_apc', 'APC');
+ SS_Cache::pick_backend('primary_apc', 'any', 10);
+
+### Two-Levels
+
+This backend is an hybrid one. It stores cache records in two other backends:
+a fast one (but limited) like Apc, Memcache... and a "slow" one like File or Sqlite.
+
+ :::php
+ SS_Cache::add_backend('two_level', 'Two-Levels', array(
+ 'slow_backend' => 'File',
+ 'fast_backend' => 'APC',
+ 'slow_backend_options' => array(
+ 'cache_dir' => TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache'
+ )
+ ));
+ SS_Cache::pick_backend('two_level', 'any', 10);
\ No newline at end of file
diff --git a/model/Aggregate.php b/model/Aggregate.php
index 372843299..84cc105e2 100644
--- a/model/Aggregate.php
+++ b/model/Aggregate.php
@@ -43,19 +43,24 @@ class Aggregate extends ViewableData {
protected static function cache() {
return self::$cache ? self::$cache : (self::$cache = SS_Cache::factory('aggregate'));
}
-
- /** Clear the aggregate cache for a given type, or pass nothing to clear all aggregate caches */
+
+ /**
+ * Clear the aggregate cache for a given type, or pass nothing to clear all aggregate caches.
+ * {@link $class} is just effective if the cache backend supports tags.
+ */
public static function flushCache($class=null) {
$cache = self::cache();
-
- if (!$class || $class == 'DataObject') {
+ $capabilities = $cache->getBackend()->getCapabilities();
+ if($capabilities['tags'] && (!$class || $class == 'DataObject')) {
$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('aggregate'));
- } else {
+ } elseif($capabilities['tags']) {
$tags = ClassInfo::ancestry($class);
foreach($tags as &$tag) {
$tag = preg_replace('/[^a-zA-Z0-9_]/', '_', $tag);
}
$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, $tags);
+ } else {
+ $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
}
}