API Use symfony/cache (fixes #6252)

This commit is contained in:
Ingo Schommer 2017-02-24 08:39:57 +13:00
parent 84ee2c1448
commit d220ca3f67
24 changed files with 535 additions and 481 deletions

View File

@ -1,6 +1,6 @@
<?php <?php
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
use SilverStripe\View\Parsers\ShortcodeParser; use SilverStripe\View\Parsers\ShortcodeParser;
@ -32,12 +32,6 @@ ShortcodeParser::get('regenerator')
// @todo // @todo
// ->register('dbfile_link', array('DBFile', 'handle_shortcode')) // ->register('dbfile_link', array('DBFile', 'handle_shortcode'))
// Zend_Cache temp directory setting
$_ENV['TMPDIR'] = TEMP_FOLDER; // for *nix
$_ENV['TMP'] = TEMP_FOLDER; // for Windows
Cache::set_cache_lifetime('GDBackend_Manipulations', null, 100);
// If you don't want to see deprecation errors for the new APIs, change this to 3.2.0-dev. // If you don't want to see deprecation errors for the new APIs, change this to 3.2.0-dev.
Deprecation::notification_version('3.2.0'); Deprecation::notification_version('3.2.0');

22
_config/cache.yml Normal file
View File

@ -0,0 +1,22 @@
---
Name: corecache
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\DefaultCacheFactory'
constructor:
directory: `TEMP_FOLDER`
Psr\SimpleCache\CacheInterface.GDBackend_Manipulations:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "GDBackend_Manipulations"
defaultLifetime: 100
Psr\SimpleCache\CacheInterface.cacheblock:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "cacheblock"
defaultLifetime: 600
Psr\SimpleCache\CacheInterface.LeftAndMain_CMSVersion:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "LeftAndMain_CMSVersion"

View File

@ -17,7 +17,7 @@ use SilverStripe\Control\Controller;
use SilverStripe\Control\PjaxResponseNegotiator; use SilverStripe\Control\PjaxResponseNegotiator;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
@ -2020,9 +2020,9 @@ class LeftAndMain extends Controller implements PermissionProvider
// Tries to obtain version number from composer.lock if it exists // Tries to obtain version number from composer.lock if it exists
$composerLockPath = BASE_PATH . '/composer.lock'; $composerLockPath = BASE_PATH . '/composer.lock';
if (file_exists($composerLockPath)) { if (file_exists($composerLockPath)) {
$cache = Cache::factory('LeftAndMain_CMSVersion'); $cache = Injector::inst()->get(CacheInterface::class . '.LeftAndMain_CMSVersion');
$cacheKey = filemtime($composerLockPath); $cacheKey = (string)filemtime($composerLockPath);
$versions = $cache->load($cacheKey); $versions = $cache->get($cacheKey);
if ($versions) { if ($versions) {
$versions = json_decode($versions, true); $versions = json_decode($versions, true);
} else { } else {
@ -2038,7 +2038,7 @@ class LeftAndMain extends Controller implements PermissionProvider
$versions[$package->name] = $package->version; $versions[$package->name] = $package->version;
} }
} }
$cache->save(json_encode($versions), $cacheKey); $cache->set($cacheKey, json_encode($versions));
} }
} }
} }

View File

@ -23,6 +23,7 @@
"symfony/yaml": "~2.7", "symfony/yaml": "~2.7",
"embed/embed": "^2.6", "embed/embed": "^2.6",
"swiftmailer/swiftmailer": "~5.4", "swiftmailer/swiftmailer": "~5.4",
"symfony/cache": "^3.3@dev",
"symfony/config": "^2.8", "symfony/config": "^2.8",
"symfony/translation": "^2.8", "symfony/translation": "^2.8",
"vlucas/phpdotenv": "^2.4" "vlucas/phpdotenv": "^2.4"

View File

@ -30,8 +30,7 @@ When we render `$Counter` to the template we would expect the value to increase
## Partial caching ## Partial caching
Partial caching is a feature that allows the caching of just a portion of a page. Instead of fetching the required data Partial caching is a feature that allows the caching of just a portion of a page. Instead of fetching the required data
from the database to display, the contents of the area are fetched from the `TEMP_FOLDER` file-system pre-rendered and from the database to display, the contents of the area are fetched from a [cache backend](../performance/caching).
ready to go. More information about Partial caching is in the [Performance](../performance) guide.
:::ss :::ss
<% cached 'MyCachedContent', LastEdited %> <% cached 'MyCachedContent', LastEdited %>

View File

@ -1,10 +1,10 @@
# Caching # Caching
## Built-In Caches ## Overview
The framework uses caches to store infrequently changing values. The framework uses caches to store infrequently changing values.
By default, the storage mechanism is simply the filesystem, although By default, the storage mechanism chooses the most performant adapter available
other cache backends can be configured. All caches use the [api:Cache] API. (PHP7 opcache, APC, or filesystem). Other cache backends can be configured.
The most common caches are manifests of various resources: The most common caches are manifests of various resources:
@ -21,136 +21,170 @@ executing the action is limited to the following cases when performed via a web
* A user is logged in with ADMIN permissions * A user is logged in with ADMIN permissions
* An error occurs during startup * An error occurs during startup
## The Cache API ## Configuration
The [api:Cache] class provides a bunch of static functions wrapping the Zend_Cache system We are using the [PSR-16](http://www.php-fig.org/psr/psr-16/) standard ("SimpleCache")
in something a little more easy to use with the SilverStripe config system. for caching, through the [symfony/cache](https://symfony.com/doc/current/components/cache.html) library.
Note that this library describes usage of [PSR-6](http://www.php-fig.org/psr/psr-6/) by default,
but also exposes caches following the PSR-16 interface.
A `Zend_Cache` has both a frontend (determines how to get the value to cache, Cache objects are configured via YAML
and how to serialize it for storage) and a backend (handles the actual and SilverStripe's [dependency injection](/developer-guides/extending/injector) system.
storage).
Rather than require library code to specify the backend directly, cache :::yml
consumers provide a name for the cache backend they want. The end developer SilverStripe\Core\Injector\Injector:
can then specify which backend to use for each name in their project's Psr\SimpleCache\CacheInterface.myCache:
configuration. They can also use 'all' to provide a backend for all named factory: SilverStripe\Core\Cache\CacheFactory
caches. constructor:
namespace: "myCache"
End developers provide a set of named backends, then pick the specific Cache objects are instantiated through a [CacheFactory](SilverStripe\Core\Cache\CacheFactory),
backend for each named cache. There is a default File cache set up as the which determines which cache adapter is used (see "Adapters" below for details).
'default' named backend, which is assigned to 'all' named caches. This factory allows us you to globally define an adapter for all cache instances.
## Using Caches :::php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
Caches can be created and retrieved through the `Cache::factory()` method. Caches are namespaced, which might allow granular clearing of a particular cache without affecting others.
The returned object is of type `Zend_Cache`. In our example, the namespace is "myCache", expressed in the service name as
`Psr\SimpleCache\CacheInterface.myCache`. We recommend the `::class` short-hand to compose the full service name.
Clearing caches by namespace is dependant on the used adapter: While the `FilesystemCache` adapter clears only the namespaced cache,
a `MemcachedCache` adapter will clear all caches regardless of namespace, since the underlying memcached
service doesn't support this. See "Invalidation" for alternative strategies.
## Usage
Cache objects follow the [PSR-16](http://www.php-fig.org/psr/psr-16/) class interface.
:::php :::php
// foo is any name (try to be specific), and is used to get configuration use Psr\SimpleCache\CacheInterface
// & storage info $cache = Injector::inst()->get(CacheInterface::class . '.myCache');
$cache = Cache::factory('foo');
if (!($result = $cache->load($cachekey))) {
$result = caluate some how;
$cache->save($result, $cachekey);
}
return $result;
Normally there's no need to remove things from the cache - the cache // create a new item by trying to get it from the cache
backends clear out entries based on age and maximum allocated storage. If you $myValue = $cache->get('myCacheKey');
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, // set a value and save it via the adapter
e.g. in development mode. $cache->set('myCacheKey', 1234);
// retrieve the cache item
if (!$cache->has('myCacheKey')) {
// ... item does not exists in the cache
}
## Invalidation
:::php Caches can be invalidated in different ways. The easiest is to actively clear the
// Disables all caches entire cache. If the adapter supports namespaced cache clearing,
Cache::set_cache_lifetime('any', -1, 100); this will only affect a subset of cache keys ("myCache" in this example):
You can also specifically clean a cache. :::php
Keep in mind that `Zend_Cache::CLEANING_MODE_ALL` deletes all cache use Psr\SimpleCache\CacheInterface
entries across all caches, not just for the 'foo' cache in the example below. $cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// remove all items in this (namespaced) cache
$cache->clear();
You can also delete a single item based on it's cache key:
:::php :::php
$cache = Cache::factory('foo'); use Psr\SimpleCache\CacheInterface
$cache->clean(Zend_Cache::CLEANING_MODE_ALL); $cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// remove the cache item
$cache->delete('myCacheKey');
A single element can be invalidated through its cache key. Individual cache items can define a lifetime, after which the cached value is marked as expired:
:::php :::php
$cache = Cache::factory('foo'); use Psr\SimpleCache\CacheInterface
$cache->remove($cachekey); $cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// remove the cache item
$cache->set('myCacheKey', 'myValue', 300); // cache for 300 seconds
If a lifetime isn't defined on the `set()` call, it'll use the adapter default.
In order to increase the chance of your cache actually being hit, In order to increase the chance of your cache actually being hit,
it often pays to increase the lifetime of caches ("TTL"). it often pays to increase the lifetime of caches.
It defaults to 10 minutes (600s) in SilverStripe, which can be You can also set your lifetime to `0`, which means they won't expire.
quite short depending on how often your data changes. Since many adapters don't have a way to actively remove expired caches,
Keep in mind that data expiry should primarily be handled by your cache key, you need to be careful with resources here (e.g. filesystem space).
e.g. by including the `LastEdited` value when caching `DataObject` results.
:::php :::yml
// set all caches to 3 hours SilverStripe\Core\Injector\Injector:
Cache::set_cache_lifetime('any', 60*60*3); Psr\SimpleCache\CacheInterface.cacheblock:
constructor:
defaultLifetime: 3600
## Alternative Cache Backends In most cases, invalidation and expiry should be handled by your cache key.
For example, including the `LastEdited` value when caching `DataObject` results
will automatically create a new cache key when the object has been changed.
The following example caches a member's group names, and automatically
creates a new cache key when any group is edited. Depending on the used adapter,
old cache keys will be garbage collected as the cache fills up.
By default, SilverStripe uses a file-based caching backend. :::php
Together with a file stat cache like [APC](http://us2.php.net/manual/en/book.apc.php) use Psr\SimpleCache\CacheInterface
this is reasonably quick, but still requires access to slow disk I/O. $cache = Injector::inst()->get(CacheInterface::class . '.myCache');
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. // Automatically changes when any group is edited
$cacheKey = implode(['groupNames', $member->ID, Groups::get()->max('LastEdited')]);
$cache->set($cacheKey, $member->Groups()->column('Title'));
## Cleaning caches on flush=1 requests If `?flush=1` is requested in the URL, this will trigger a call to `flush()` on
any classes that implement the [Flushable](/developer_guides/execution_pipeline/flushable/)
interface. Use this interface to trigger `clear()` on your caches.
If `?flush=1` is requested in the URL, e.g. http://mysite.com?flush=1, this will trigger a call to `flush()` on ## Adapters
any classes that implement the `Flushable` interface. Using this, you can trigger your caches to clean.
See [reference documentation on Flushable](/developer_guides/execution_pipeline/flushable/) for implementation details. SilverStripe tries to identify the most performant cache available on your system
through the [DefaultCacheFactory](api:SilverStripe\Core\Cache\DefaultCacheFactory) implementation:
### Memcached * - `PhpFilesCache` (PHP 5.6 or PHP 7 with [opcache](http://php.net/manual/en/book.opcache.php) enabled).
This cache has relatively low [memory defaults](http://php.net/manual/en/opcache.configuration.php#ini.opcache.memory-consumption).
We recommend increasing it for large applications, or enabling the
[file_cache fallback](http://php.net/manual/en/opcache.configuration.php#ini.opcache.file-cache)
* - `ApcuCache` (requires APC) with a `FilesystemCache` fallback (for larger cache volumes)
* - `FilesystemCache` if none of the above is available
The library supports various [cache adapters](https://github.com/symfony/cache/tree/master/Simple)
which can provide better performance, particularly in multi-server environments with shared caches like Memcached.
This backends stores cache records into a [memcached](http://www.danga.com/memcached/) Since we're using dependency injection to create caches,
server. memcached is a high-performance, distributed memory object caching system. you need to define a factory for a particular adapter,
To use this backend, you need a memcached daemon and the memcache PECL extension. following the `SilverStripe\Core\Cache\CacheFactory` interface.
Different adapters will require different constructor arguments.
We've written factories for the most common cache scenarios:
`FilesystemCacheFactory`, `MemcachedCacheFactory` and `ApcuCacheFactory`.
:::php Example: Configure core caches to use [memcached](http://www.danga.com/memcached/),
// _config.php which requires the [memcached PHP extension](http://php.net/memcached),
Cache::add_backend( and takes a `MemcachedClient` instance as a constructor argument.
'primary_memcached',
'Memcached',
array(
'servers' => array(
'host' => 'localhost',
'port' => 11211,
'persistent' => true,
'weight' => 1,
'timeout' => 5,
'retry_interval' => 15,
'status' => true,
'failure_callback' => null
)
)
);
Cache::pick_backend('primary_memcached', 'any', 10);
### APC :::yml
---
After:
- '#corecache'
---
SilverStripe\Core\Injector\Injector:
MemcachedClient:
class: 'Memcached'
calls:
- [ addServer, [ 'localhost', 11211 ] ]
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\MemcachedCacheFactory'
constructor:
client: '%$MemcachedClient
This backends stores cache records in shared memory through the [APC](http://pecl.php.net/package/APC) ## Additional Caches
(Alternative PHP Cache) extension (which is of course need for using this backend).
:::php Unfortunately not all caches are configurable via cache adapters.
Cache::add_backend('primary_apc', 'APC');
Cache::pick_backend('primary_apc', 'any', 10);
### Two-Levels * [SSViewer](api:SilverStripe\View\SSViewer) writes compiled templates as PHP files to the filesystem
(in order to achieve opcode caching on `include()` calls)
This backend is an hybrid one. It stores cache records in two other backends: * [ConfigManifest](api:SilverStripe\Core\Manifest\ConfigManifest) is hardcoded to use `FilesystemCache`
a fast one (but limited) like Apc, Memcache... and a "slow" one like File or Sqlite. * [ClassManifest](api:SilverStripe\Core\Manifest\ClassManifest) and [ThemeManifest](api:SilverStripe\View\ThemeManifest)
are using a custom `ManifestCache`
:::php * [i18n](api:SilverStripe\i18n\i18n) uses `Symfony\Component\Config\ConfigCacheFactoryInterface` (filesystem-based)
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'
)
));
Cache::pick_backend('two_level', 'any', 10);

View File

@ -16,6 +16,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
* [Filesystem API](#overview-filesystem) * [Filesystem API](#overview-filesystem)
* [Template and Form API](#overview-template) * [Template and Form API](#overview-template)
* [i18n](#overview-i18n) * [i18n](#overview-i18n)
* [Cache](#overview-cache)
* [Email and Mailer](#overview-mailer) * [Email and Mailer](#overview-mailer)
* [Commit History](#commit-history) * [Commit History](#commit-history)
@ -49,6 +50,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
* Themes are now configured to cascade, where you can specify a list of themes, and have the template engine * Themes are now configured to cascade, where you can specify a list of themes, and have the template engine
search programatically through a prioritised list when resolving template and CSS file paths. search programatically through a prioritised list when resolving template and CSS file paths.
* i18n Updated to use symfony/translation over zend Framework 1. Zend_Translate has been removed. * i18n Updated to use symfony/translation over zend Framework 1. Zend_Translate has been removed.
* Replaced `Zend_Cache` and the `Cache` API with a PSR-16 implementation (symfony/cache)
* _ss_environment.php files have been removed in favour of `.env` and "real" environment variables. * _ss_environment.php files have been removed in favour of `.env` and "real" environment variables.
## <a name="upgrading"></a>Upgrading ## <a name="upgrading"></a>Upgrading
@ -1473,6 +1475,93 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
* `i18n::get_common_locales()` removed. * `i18n::get_common_locales()` removed.
* `i18n.common_locales` config removed * `i18n.common_locales` config removed
### <a name="overview-cache"></a>Cache API
We have replaced the unsupported `Zend_Cache` library with [symfony/cache](https://github.com/symfony/cache).
This also allowed us to remove SilverStripe's `Cache` API and use dependency injection with a standard
[PSR-16](http://www.php-fig.org/psr/psr-16/) cache interface instead.
#### Usage Changes
Caches should be retrieved through `Injector` instead of `Cache::factory()`,
and have a slightly different API (e.g. `set()` instead of `save()`).
Before:
:::php
$cache = Cache::factory('myCache');
// create a new item by trying to get it from the cache
$myValue = $cache->load('myCacheKey');
// set a value and save it via the adapter
$cache->save(1234, 'myCacheKey');
// retrieve the cache item
if (!$cache->load('myCacheKey')) {
// ... item does not exists in the cache
}
// Remove a cache key
$cache->remove('myCacheKey');
After:
:::php
use Psr\SimpleCache\CacheInterface;
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// create a new item by trying to get it from the cache
$myValue = $cache->get('myCacheKey');
// set a value and save it via the adapter
$cache->set('myCacheKey', 1234);
// retrieve the cache item
if (!$cache->has('myCacheKey')) {
// ... item does not exists in the cache
}
$cache->delete('myCacheKey');
#### Configuration Changes
Caches are now configured through dependency injection services instead of PHP.
See our ["Caching" docs](/developer-guides/performance/caching) for more details.
Before (`mysite/_config.php`):
:::php
Cache::add_backend(
'primary_memcached',
'Memcached',
array(
'servers' => array(
'host' => 'localhost',
'port' => 11211,
)
)
);
Cache::pick_backend('primary_memcached', 'any', 10);
After (`mysite/_config/config.yml`):
:::yml
---
After:
- '#corecache'
---
SilverStripe\Core\Injector\Injector:
MemcachedClient:
class: 'Memcached'
calls:
- [ addServer, [ 'localhost', 11211 ] ]
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\MemcachedCacheFactory'
constructor:
client: '%$MemcachedClient
### <a name="overview-mailer"></a>Email and Mailer ### <a name="overview-mailer"></a>Email and Mailer
#### <a name="overview-mailer-api"></a>Email Additions / Changes #### <a name="overview-mailer-api"></a>Email Additions / Changes

View File

@ -4,12 +4,11 @@ namespace SilverStripe\Assets;
use SilverStripe\Assets\Storage\AssetContainer; use SilverStripe\Assets\Storage\AssetContainer;
use SilverStripe\Assets\Storage\AssetStore; use SilverStripe\Assets\Storage\AssetStore;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Object; use SilverStripe\Core\Object;
use SilverStripe\Core\Flushable; use SilverStripe\Core\Flushable;
use InvalidArgumentException; use InvalidArgumentException;
use Zend_Cache;
use Zend_Cache_Core;
/** /**
* A wrapper class for GD-based images, with lots of manipulation functions. * A wrapper class for GD-based images, with lots of manipulation functions.
@ -25,7 +24,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected $gd; protected $gd;
/** /**
* @var Zend_Cache_Core * @var \Psr\SimpleCache\CacheInterface
*/ */
protected $cache; protected $cache;
@ -66,7 +65,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public function __construct(AssetContainer $assetContainer = null) public function __construct(AssetContainer $assetContainer = null)
{ {
parent::__construct(); parent::__construct();
$this->cache = Cache::factory('GDBackend_Manipulations'); $this->cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
if ($assetContainer) { if ($assetContainer) {
$this->loadFromContainer($assetContainer); $this->loadFromContainer($assetContainer);
@ -219,7 +218,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public function failedResample($arg = null) public function failedResample($arg = null)
{ {
$key = sha1(implode('|', func_get_args())); $key = sha1(implode('|', func_get_args()));
return (bool)$this->cache->load($key); return (bool)$this->cache->get($key);
} }
/** /**
@ -259,7 +258,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected function markFailed($arg = null) protected function markFailed($arg = null)
{ {
$key = sha1(implode('|', func_get_args())); $key = sha1(implode('|', func_get_args()));
$this->cache->save('1', $key); $this->cache->set($key, '1');
} }
/** /**
@ -270,7 +269,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected function markSucceeded($arg = null) protected function markSucceeded($arg = null)
{ {
$key = sha1(implode('|', func_get_args())); $key = sha1(implode('|', func_get_args()));
$this->cache->save('0', $key); $this->cache->set($key, '0');
} }
@ -762,8 +761,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public static function flush() public static function flush()
{ {
// Clear factory $cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$cache = Cache::factory('GDBackend_Manipulations'); $cache->clear();
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
} }
} }

View File

@ -1,201 +0,0 @@
<?php
namespace SilverStripe\Core;
use Zend_Cache;
use Zend_Cache_Core;
/**
* The `[api: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.
*
* @see https://docs.silverstripe.org/en/3.4/developer_guides/performance/caching/
*/
class Cache
{
/**
* @var array $backends
*/
protected static $backends = array();
/**
* @var array $backend_picks
*/
protected static $backend_picks = array();
/**
* @var array $cache_lifetime
*/
protected static $cache_lifetime = array();
/**
* Initialize the 'default' named cache backend.
*/
protected static function init()
{
if (!isset(self::$backends['default'])) {
$cachedir = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache';
if (!is_dir($cachedir)) {
mkdir($cachedir);
}
/** @skipUpgrade */
self::$backends['default'] = array(
'File',
array(
'cache_dir' => $cachedir
)
);
self::$cache_lifetime['default'] = array(
'lifetime' => 600,
'priority' => 1
);
}
}
/**
* Add a new named cache backend.
*
* @see http://framework.zend.com/manual/en/zend.cache.html
*
* @param string $name The name of this backend as a freeform string
* @param string $type The Zend_Cache backend ('File' or 'Sqlite' or ...)
* @param array $options The Zend_Cache backend options
*/
public static function add_backend($name, $type, $options = array())
{
self::init();
self::$backends[$name] = array($type, $options);
}
/**
* Pick a named cache backend for a particular named cache.
*
* The priority call with the highest number will be the actual backend
* picked. A backend picked for a specific cache name will always be used
* instead of 'any' if it exists, no matter the priority.
*
* @param string $name The name of the backend, as passed as the first argument to add_backend
* @param string $for The name of the cache to pick this backend for (or 'any' for any backend)
* @param integer $priority The priority of this pick
*/
public static function pick_backend($name, $for, $priority = 1)
{
self::init();
$current = -1;
if (isset(self::$backend_picks[$for])) {
$current = self::$backend_picks[$for]['priority'];
}
if ($priority >= $current) {
self::$backend_picks[$for] = array(
'name' => $name,
'priority' => $priority
);
}
}
/**
* Return the cache lifetime for a particular named cache.
*
* @param string $for
*
* @return string
*/
public static function get_cache_lifetime($for)
{
if (isset(self::$cache_lifetime[$for])) {
return self::$cache_lifetime[$for];
}
return null;
}
/**
* Set the cache lifetime for a particular named cache
*
* @param string $for The name of the cache to set this lifetime for (or 'any' for all backends)
* @param integer $lifetime The lifetime of an item of the cache, in seconds, or -1 to disable caching
* @param integer $priority The priority. The highest priority setting is used. Unlike backends, 'any' is not
* special in terms of priority.
*/
public static function set_cache_lifetime($for, $lifetime = 600, $priority = 1)
{
self::init();
$current = -1;
if (isset(self::$cache_lifetime[$for])) {
$current = self::$cache_lifetime[$for]['priority'];
}
if ($priority >= $current) {
self::$cache_lifetime[$for] = array(
'lifetime' => $lifetime,
'priority' => $priority
);
}
}
/**
* Build a cache object.
*
* @see http://framework.zend.com/manual/en/zend.cache.html
*
* @param string $for The name of the cache to build
* @param string $frontend (optional) The type of Zend_Cache frontend
* @param array $frontendOptions (optional) Any frontend options to use.
* @return Zend_Cache_Core The cache object
*/
public static function factory($for, $frontend = 'Output', $frontendOptions = null)
{
self::init();
$backend_name = 'default';
$backend_priority = -1;
$cache_lifetime = self::$cache_lifetime['default']['lifetime'];
$lifetime_priority = -1;
foreach (array('any', $for) as $name) {
if (isset(self::$backend_picks[$name])) {
if (self::$backend_picks[$name]['priority'] > $backend_priority) {
$backend_name = self::$backend_picks[$name]['name'];
$backend_priority = self::$backend_picks[$name]['priority'];
}
}
if (isset(self::$cache_lifetime[$name])) {
if (self::$cache_lifetime[$name]['priority'] > $lifetime_priority) {
$cache_lifetime = self::$cache_lifetime[$name]['lifetime'];
$lifetime_priority = self::$cache_lifetime[$name]['priority'];
}
}
}
$backend = self::$backends[$backend_name];
$basicOptions = array('cache_id_prefix' => $for);
if ($cache_lifetime >= 0) {
$basicOptions['lifetime'] = $cache_lifetime;
} else {
$basicOptions['caching'] = false;
}
$frontendOptions = $frontendOptions ? array_merge($basicOptions, $frontendOptions) : $basicOptions;
require_once 'Zend/Cache.php';
return Zend_Cache::factory(
$frontend,
$backend[0],
$frontendOptions,
$backend[1]
);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\ApcuCache;
use Memcached;
class ApcuCacheFactory implements CacheFactory
{
/**
* @var string
*/
protected $version;
/**
* @param string $version
*/
public function __construct($version = null)
{
$this->version = $version;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(ApcuCache::class, false, [
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0,
$this->version
]);
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Factory as InjectorFactory;
interface CacheFactory extends InjectorFactory
{
/**
* Note: While the returned object is used as a singleton (by the originating Injector->get() call),
* this cache object shouldn't be a singleton itself - it has varying constructor args for the same service name.
*
* @param string $class
* @param array $args
* @return CacheInterface
*/
public function create($service, array $params = array());
}

View File

@ -0,0 +1,79 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\ApcuCache;
use Symfony\Component\Cache\Simple\ChainCache;
use Symfony\Component\Cache\Simple\PhpFilesCache;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
/**
* Returns the most performant combination of caches available on the system:
* - `PhpFilesCache` (PHP 7 with opcache enabled)
* - `ApcuCache` (requires APC) with a `FilesystemCache` fallback (for larger cache volumes)
* - `FilesystemCache` if none of the above is available
*
* Modelled after `Symfony\Component\Cache\Adapter\AbstractAdapter::createSystemCache()`
*/
class DefaultCacheFactory implements CacheFactory
{
/**
* @var string Absolute directory path
*/
protected $directory;
/**
* @var string APC version for apcu_add()
*/
protected $version;
/**
* @param string $directory
* @param string $version
*/
public function __construct($directory, $version = null)
{
$this->directory = $directory;
$this->version = $version;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
$namespace = (isset($args['namespace'])) ? $args['namespace'] : '';
$defaultLifetime = (isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0;
$version = $this->version;
$directory = $this->directory;
$apcuSupported = null;
$phpFilesSupported = null;
if (null === $apcuSupported) {
$apcuSupported = ApcuAdapter::isSupported();
}
if (!$apcuSupported && null === $phpFilesSupported) {
$phpFilesSupported = PhpFilesAdapter::isSupported();
}
if ($phpFilesSupported) {
$opcache = Injector::inst()->create(PhpFilesCache::class, false, [$namespace, $defaultLifetime, $directory]);
return $opcache;
}
$fs = Injector::inst()->create(FilesystemCache::class, false, [$namespace, $defaultLifetime, $directory]);
if (!$apcuSupported) {
return $fs;
}
$apcu = Injector::inst()->create(ApcuCache::class, false, [$namespace, (int) $defaultLifetime / 5, $version]);
return Injector::inst()->create(ChainCache::class, false, [[$apcu, $fs]]);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\FilesystemCache;
class FilesystemCacheFactory implements CacheFactory
{
/**
* @var string Absolute directory path
*/
protected $directory;
/**
* @param string $directory
*/
public function __construct($directory)
{
$this->directory = $directory;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(FilesystemCache::class, false, [
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0,
$this->directory
]);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\MemcachedCache;
use Memcached;
class MemcachedCacheFactory implements CacheFactory
{
/**
* @var Memcached
*/
protected $memcachedClient;
/**
* @param Memcached $memcachedClient
*/
public function __construct(Memcached $memcachedClient)
{
$this->memcachedClient = $memcachedClient;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(MemcachedCache::class, false, [
$this->memcachedClient,
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0
]);
}
}

View File

@ -54,14 +54,6 @@ mb_regex_encoding('UTF-8');
*/ */
gc_enable(); gc_enable();
/**
* Include the Zend autoloader. This will be removed in the near future.
*/
if (file_exists('thirdparty/Zend/Loader/Autoloader.php')) {
require_once 'thirdparty/Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
}
// Initialise the dependency injector as soon as possible, as it is // Initialise the dependency injector as soon as possible, as it is
// subsequently used by some of the following code // subsequently used by some of the following code
$injector = new Injector(array('locator' => 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator')); $injector = new Injector(array('locator' => 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator'));

View File

@ -7,10 +7,9 @@ use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\DAG; use SilverStripe\Core\Config\DAG;
use SilverStripe\Core\Config\DAG_CyclicException; use SilverStripe\Core\Config\DAG_CyclicException;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache; use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Parser;
use Traversable; use Traversable;
use Zend_Cache_Core;
/** /**
* A utility class which builds a manifest of configuration items * A utility class which builds a manifest of configuration items
@ -28,7 +27,7 @@ class ConfigManifest
protected $includeTests; protected $includeTests;
/** /**
* @var Zend_Cache_Core * @var FilesystemCache
*/ */
protected $cache; protected $cache;
@ -114,15 +113,15 @@ class ConfigManifest
$this->key = sha1($base).'_'; $this->key = sha1($base).'_';
$this->includeTests = $includeTests; $this->includeTests = $includeTests;
// Get the Zend Cache to load/store cache into // Get a cache singleton
$this->cache = $this->getCache(); $this->cache = $this->getCache();
// Unless we're forcing regen, try loading from cache // Unless we're forcing regen, try loading from cache
if (!$forceRegen) { if (!$forceRegen) {
// The PHP config sources are always needed // The PHP config sources are always needed
$this->phpConfigSources = $this->cache->load($this->key.'php_config_sources'); $this->phpConfigSources = $this->cache->get($this->key.'php_config_sources');
// Get the variant key spec // Get the variant key spec
$this->variantKeySpec = $this->cache->load($this->key.'variant_key_spec'); $this->variantKeySpec = $this->cache->get($this->key.'variant_key_spec');
} }
// If we don't have a variantKeySpec (because we're forcing regen, or it just wasn't in the cache), generate it // If we don't have a variantKeySpec (because we're forcing regen, or it just wasn't in the cache), generate it
@ -136,14 +135,12 @@ class ConfigManifest
/** /**
* Provides a hook for mock unit tests despite no DI * Provides a hook for mock unit tests despite no DI
* @return Zend_Cache_Core * @return \Psr\SimpleCache\CacheInterface
*/ */
protected function getCache() protected function getCache()
{ {
return Cache::factory('SS_Configuration', 'Core', array( // TODO Replace with CoreConfigCreator, see https://github.com/silverstripe/silverstripe-framework/pull/6641/files#diff-f8c9b17e06432278197a7d5c3a1043cb
'automatic_serialization' => true, return new FilesystemCache('SS_Configuration', 0, getTempFolder());
'lifetime' => null
));
} }
/** /**
@ -264,9 +261,9 @@ class ConfigManifest
$this->buildVariantKeySpec(); $this->buildVariantKeySpec();
if ($cache) { if ($cache) {
$this->cache->save($this->phpConfigSources, $this->key.'php_config_sources'); $this->cache->set($this->key.'php_config_sources', $this->phpConfigSources);
$this->cache->save($this->yamlConfigFragments, $this->key.'yaml_config_fragments'); $this->cache->set($this->key.'yaml_config_fragments', $this->yamlConfigFragments);
$this->cache->save($this->variantKeySpec, $this->key.'variant_key_spec'); $this->cache->set($this->key.'variant_key_spec', $this->variantKeySpec);
} }
} }
@ -650,12 +647,12 @@ class ConfigManifest
// given variant is stale compared to the complete set of fragments // given variant is stale compared to the complete set of fragments
if (!$this->yamlConfigFragments) { if (!$this->yamlConfigFragments) {
// First try and just load the exact variant // First try and just load the exact variant
if ($this->yamlConfig = $this->cache->load($this->key.'yaml_config_'.$this->variantKey())) { if ($this->yamlConfig = $this->cache->get($this->key.'yaml_config_'.$this->variantKey())) {
$this->yamlConfigVariantKey = $this->variantKey(); $this->yamlConfigVariantKey = $this->variantKey();
return; return;
} // Otherwise try and load the fragments so we can build the variant } // Otherwise try and load the fragments so we can build the variant
else { else {
$this->yamlConfigFragments = $this->cache->load($this->key.'yaml_config_fragments'); $this->yamlConfigFragments = $this->cache->get($this->key.'yaml_config_fragments');
} }
} }
@ -684,7 +681,7 @@ class ConfigManifest
} }
if ($cache) { if ($cache) {
$this->cache->save($this->yamlConfig, $this->key.'yaml_config_'.$this->variantKey()); $this->cache->set($this->key.'yaml_config_'.$this->variantKey(), $this->yamlConfig);
} }
// Since yamlConfig has changed, call any callbacks that are interested // Since yamlConfig has changed, call any callbacks that are interested

View File

@ -743,10 +743,10 @@ class SSTemplateParser extends Parser implements TemplateParser
// Get any condition // Get any condition
$condition = isset($res['condition']) ? $res['condition'] : ''; $condition = isset($res['condition']) ? $res['condition'] : '';
$res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL; $res['php'] .= 'if ('.$condition.'($partial = $cache->get('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL; $res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL;
$res['php'] .= $sub['php'] . PHP_EOL; $res['php'] .= $sub['php'] . PHP_EOL;
$res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL; $res['php'] .= $condition . ' $cache->set('.$key.', $val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= '}'; $res['php'] .= '}';
} }

View File

@ -4020,10 +4020,10 @@ class SSTemplateParser extends Parser implements TemplateParser
// Get any condition // Get any condition
$condition = isset($res['condition']) ? $res['condition'] : ''; $condition = isset($res['condition']) ? $res['condition'] : '';
$res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL; $res['php'] .= 'if ('.$condition.'($partial = $cache->get('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL; $res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL;
$res['php'] .= $sub['php'] . PHP_EOL; $res['php'] .= $sub['php'] . PHP_EOL;
$res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL; $res['php'] .= $condition . ' $cache->set('.$key.', $val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= '}'; $res['php'] .= '}';
} }

View File

@ -4,7 +4,7 @@ namespace SilverStripe\View;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Flushable; use SilverStripe\Core\Flushable;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
@ -14,9 +14,6 @@ use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Security\Permission; use SilverStripe\Security\Permission;
use InvalidArgumentException; use InvalidArgumentException;
use Zend_Cache_Backend_ExtendedInterface;
use Zend_Cache;
use Zend_Cache_Core;
/** /**
* Parses a template file with an *.ss file extension. * Parses a template file with an *.ss file extension.
@ -466,17 +463,8 @@ class SSViewer implements Flushable
public static function flush_cacheblock_cache($force = false) public static function flush_cacheblock_cache($force = false)
{ {
if (!self::$cacheblock_cache_flushed || $force) { if (!self::$cacheblock_cache_flushed || $force) {
$cache = Cache::factory('cacheblock'); $cache = Injector::inst()->get(CacheInterface::class . '.cacheblock');
$backend = $cache->getBackend(); $cache->clear();
if ($backend instanceof Zend_Cache_Backend_ExtendedInterface
&& ($capabilities = $backend->getCapabilities())
&& $capabilities['tags']
) {
$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $cache->getTags());
} else {
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
}
self::$cacheblock_cache_flushed = true; self::$cacheblock_cache_flushed = true;
@ -484,14 +472,14 @@ class SSViewer implements Flushable
} }
/** /**
* @var Zend_Cache_Core * @var CacheInterface
*/ */
protected $partialCacheStore = null; protected $partialCacheStore = null;
/** /**
* Set the cache object to use when storing / retrieving partial cache blocks. * Set the cache object to use when storing / retrieving partial cache blocks.
* *
* @param Zend_Cache_Core $cache * @param CacheInterface $cache
*/ */
public function setPartialCacheStore($cache) public function setPartialCacheStore($cache)
{ {
@ -501,11 +489,11 @@ class SSViewer implements Flushable
/** /**
* Get the cache object to use when storing / retrieving partial cache blocks. * Get the cache object to use when storing / retrieving partial cache blocks.
* *
* @return Zend_Cache_Core * @return CacheInterface
*/ */
public function getPartialCacheStore() public function getPartialCacheStore()
{ {
return $this->partialCacheStore ? $this->partialCacheStore : Cache::factory('cacheblock'); return $this->partialCacheStore ? $this->partialCacheStore : Injector::inst()->get(CacheInterface::class . '.cacheblock');
} }
/** /**

View File

@ -3,7 +3,8 @@
namespace SilverStripe\Assets\Tests; namespace SilverStripe\Assets\Tests;
use SilverStripe\Assets\GDBackend; use SilverStripe\Assets\GDBackend;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
/** /**
@ -192,9 +193,9 @@ class GDTest extends SapphireTest
$gd->loadFrom($fullPath); $gd->loadFrom($fullPath);
// Cache should refer to this file // Cache should refer to this file
$cache = Cache::factory('GDBackend_Manipulations'); $cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$key = sha1(implode('|', array($fullPath, filemtime($fullPath)))); $key = sha1(implode('|', array($fullPath, filemtime($fullPath))));
$data = $cache->load($key); $data = $cache->get($key);
$this->assertEquals('1', $data); $this->assertEquals('1', $data);
} }

View File

@ -1,77 +0,0 @@
<?php
namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Cache;
use SilverStripe\Dev\SapphireTest;
class CacheTest extends SapphireTest
{
public function testCacheBasics()
{
$cache = Cache::factory('test');
$cache->save('Good', 'cachekey');
$this->assertEquals('Good', $cache->load('cachekey'));
}
public function testCacheCanBeDisabled()
{
Cache::set_cache_lifetime('test', -1, 10);
$cache = Cache::factory('test');
$cache->save('Good', 'cachekey');
$this->assertFalse($cache->load('cachekey'));
}
public function testCacheLifetime()
{
Cache::set_cache_lifetime('test', 0.5, 20);
$cache = Cache::factory('test');
$this->assertEquals(0.5, $cache->getOption('lifetime'));
$cache->save('Good', 'cachekey');
$this->assertEquals('Good', $cache->load('cachekey'));
// As per documentation, sleep may not sleep for the amount of time you tell it to sleep for
// This loop can make sure it *does* sleep for that long
$endtime = time() + 2;
while (time() < $endtime) {
// Sleep for another 2 seconds!
// This may end up sleeping for 4 seconds, but it's awwwwwwwright.
sleep(2);
}
$this->assertFalse($cache->load('cachekey'));
}
public function testCacheSeperation()
{
$cache1 = Cache::factory('test1');
$cache2 = Cache::factory('test2');
$cache1->save('Foo', 'cachekey');
$cache2->save('Bar', 'cachekey');
$this->assertEquals('Foo', $cache1->load('cachekey'));
$this->assertEquals('Bar', $cache2->load('cachekey'));
$cache1->remove('cachekey');
$this->assertFalse($cache1->load('cachekey'));
$this->assertEquals('Bar', $cache2->load('cachekey'));
}
public function testCacheDefault()
{
Cache::set_cache_lifetime('default', 1200);
$default = Cache::get_cache_lifetime('default');
$this->assertEquals(1200, $default['lifetime']);
$cache = Cache::factory('somethingnew');
$this->assertEquals(1200, $cache->getOption('lifetime'));
}
}

View File

@ -7,7 +7,7 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Manifest\ConfigManifest; use SilverStripe\Core\Manifest\ConfigManifest;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use ReflectionProperty; use ReflectionProperty;
use Zend_Cache_Core; use Symfony\Component\Cache\Simple\ArrayCache;
class ConfigManifestTest extends SapphireTest class ConfigManifestTest extends SapphireTest
{ {
@ -34,13 +34,13 @@ class ConfigManifestTest extends SapphireTest
/** /**
* A helper method to return a mock of the cache in order to test expectations and reduce dependency * A helper method to return a mock of the cache in order to test expectations and reduce dependency
* *
* @return Zend_Cache_Core * @return \PHPUnit_Framework_MockObject_MockObject
*/ */
protected function getCacheMock() protected function getCacheMock()
{ {
return $this->getMock( return $this->getMock(
'Zend_Cache_Core', ArrayCache::class,
array('load', 'save'), array('set', 'get'),
array(), array(),
'', '',
false false
@ -51,7 +51,7 @@ class ConfigManifestTest extends SapphireTest
* A helper method to return a mock of the manifest in order to test expectations and reduce dependency * A helper method to return a mock of the manifest in order to test expectations and reduce dependency
* *
* @param $methods * @param $methods
* @return ConfigManifest * @return \PHPUnit_Framework_MockObject_MockObject
*/ */
protected function getManifestMock($methods) protected function getManifestMock($methods)
{ {
@ -82,7 +82,7 @@ class ConfigManifestTest extends SapphireTest
// Set up a cache where we expect load to never be called // Set up a cache where we expect load to never be called
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->never()) $cache->expects($this->never())
->method('load'); ->method('get');
$manifest->expects($this->any()) $manifest->expects($this->any())
->method('getCache') ->method('getCache')
@ -95,7 +95,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->atLeastOnce()) $cache->expects($this->atLeastOnce())
->method('save'); ->method('set');
$manifest->expects($this->any()) $manifest->expects($this->any())
->method('getCache') ->method('getCache')
@ -119,7 +119,7 @@ class ConfigManifestTest extends SapphireTest
// Load should be called twice // Load should be called twice
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->method('load'); ->method('get');
$manifest->expects($this->any()) $manifest->expects($this->any())
->method('getCache') ->method('getCache')
@ -133,7 +133,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->method('load') ->method('get')
->will($this->onConsecutiveCalls(false, false)); ->will($this->onConsecutiveCalls(false, false));
$manifest->expects($this->any()) $manifest->expects($this->any())
@ -151,7 +151,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->method('load') ->method('get')
->will($this->onConsecutiveCalls(array(), array())); ->will($this->onConsecutiveCalls(array(), array()));
$manifest->expects($this->any()) $manifest->expects($this->any())
@ -186,7 +186,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->will($this->returnValue(false)) ->will($this->returnValue(false))
->method('load'); ->method('get');
$manifest->expects($this->any()) $manifest->expects($this->any())
->method('getCache') ->method('getCache')
@ -204,7 +204,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->method('load') ->method('get')
->will($this->returnCallback(function ($parameter) { ->will($this->returnCallback(function ($parameter) {
if (strpos($parameter, 'variant_key_spec') !== false) { if (strpos($parameter, 'variant_key_spec') !== false) {
return false; return false;
@ -227,7 +227,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock(); $cache = $this->getCacheMock();
$cache->expects($this->exactly(2)) $cache->expects($this->exactly(2))
->method('load') ->method('get')
->will($this->returnCallback(function ($parameter) { ->will($this->returnCallback(function ($parameter) {
if (strpos($parameter, 'php_config_sources') !== false) { if (strpos($parameter, 'php_config_sources') !== false) {
return false; return false;

View File

@ -5,8 +5,8 @@ namespace SilverStripe\ORM\Tests;
require_once __DIR__ . "/ImageTest.php"; require_once __DIR__ . "/ImageTest.php";
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use Zend_Cache; use SilverStripe\Core\Injector\Injector;
class GDImageTest extends ImageTest class GDImageTest extends ImageTest
{ {
@ -32,8 +32,9 @@ class GDImageTest extends ImageTest
public function tearDown() public function tearDown()
{ {
$cache = Cache::factory('GDBackend_Manipulations'); $cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$cache->clean(Zend_Cache::CLEANING_MODE_ALL); $cache->clear();
parent::tearDown(); parent::tearDown();
} }
} }

View File

@ -2,11 +2,14 @@
namespace SilverStripe\View\Tests; namespace SilverStripe\View\Tests;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\Versioning\Versioned; use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\Core\Cache; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\View\SSViewer; use SilverStripe\View\SSViewer;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\NullCache;
// Not actually a data object, we just want a ViewableData object that's just for us // Not actually a data object, we just want a ViewableData object that's just for us
@ -27,8 +30,15 @@ class SSViewerCacheBlockTest extends SapphireTest
{ {
$this->data = new SSViewerCacheBlockTest\TestModel(); $this->data = new SSViewerCacheBlockTest\TestModel();
Cache::factory('cacheblock')->clean(); $cache = null;
Cache::set_cache_lifetime('cacheblock', $cacheOn ? 600 : -1); if ($cacheOn) {
$cache = new FilesystemCache('cacheblock', 0, getTempFolder()); // cache indefinitely
} else {
$cache = new NullCache();
}
Injector::inst()->registerService($cache, CacheInterface::class . '.cacheblock');
Injector::inst()->get(CacheInterface::class . '.cacheblock')->clear();
} }
protected function _runtemplate($template, $data = null) protected function _runtemplate($template, $data = null)