mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Use symfony/cache (fixes #6252)
This commit is contained in:
parent
84ee2c1448
commit
d220ca3f67
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
use SilverStripe\Core\Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
|
||||
@ -32,12 +32,6 @@ ShortcodeParser::get('regenerator')
|
||||
// @todo
|
||||
// ->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.
|
||||
Deprecation::notification_version('3.2.0');
|
||||
|
||||
|
22
_config/cache.yml
Normal file
22
_config/cache.yml
Normal 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"
|
@ -17,7 +17,7 @@ use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\PjaxResponseNegotiator;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
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
|
||||
$composerLockPath = BASE_PATH . '/composer.lock';
|
||||
if (file_exists($composerLockPath)) {
|
||||
$cache = Cache::factory('LeftAndMain_CMSVersion');
|
||||
$cacheKey = filemtime($composerLockPath);
|
||||
$versions = $cache->load($cacheKey);
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.LeftAndMain_CMSVersion');
|
||||
$cacheKey = (string)filemtime($composerLockPath);
|
||||
$versions = $cache->get($cacheKey);
|
||||
if ($versions) {
|
||||
$versions = json_decode($versions, true);
|
||||
} else {
|
||||
@ -2038,7 +2038,7 @@ class LeftAndMain extends Controller implements PermissionProvider
|
||||
$versions[$package->name] = $package->version;
|
||||
}
|
||||
}
|
||||
$cache->save(json_encode($versions), $cacheKey);
|
||||
$cache->set($cacheKey, json_encode($versions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
"symfony/yaml": "~2.7",
|
||||
"embed/embed": "^2.6",
|
||||
"swiftmailer/swiftmailer": "~5.4",
|
||||
"symfony/cache": "^3.3@dev",
|
||||
"symfony/config": "^2.8",
|
||||
"symfony/translation": "^2.8",
|
||||
"vlucas/phpdotenv": "^2.4"
|
||||
|
@ -30,8 +30,7 @@ When we render `$Counter` to the template we would expect the value to increase
|
||||
## Partial caching
|
||||
|
||||
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
|
||||
ready to go. More information about Partial caching is in the [Performance](../performance) guide.
|
||||
from the database to display, the contents of the area are fetched from a [cache backend](../performance/caching).
|
||||
|
||||
:::ss
|
||||
<% cached 'MyCachedContent', LastEdited %>
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Caching
|
||||
|
||||
## Built-In Caches
|
||||
## Overview
|
||||
|
||||
The framework uses caches to store infrequently changing values.
|
||||
By default, the storage mechanism is simply the filesystem, although
|
||||
other cache backends can be configured. All caches use the [api:Cache] API.
|
||||
By default, the storage mechanism chooses the most performant adapter available
|
||||
(PHP7 opcache, APC, or filesystem). Other cache backends can be configured.
|
||||
|
||||
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
|
||||
* An error occurs during startup
|
||||
|
||||
## The Cache API
|
||||
## Configuration
|
||||
|
||||
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.
|
||||
We are using the [PSR-16](http://www.php-fig.org/psr/psr-16/) standard ("SimpleCache")
|
||||
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,
|
||||
and how to serialize it for storage) and a backend (handles the actual
|
||||
storage).
|
||||
Cache objects are configured via YAML
|
||||
and SilverStripe's [dependency injection](/developer-guides/extending/injector) system.
|
||||
|
||||
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.
|
||||
:::yml
|
||||
SilverStripe\Core\Injector\Injector:
|
||||
Psr\SimpleCache\CacheInterface.myCache:
|
||||
factory: SilverStripe\Core\Cache\CacheFactory
|
||||
constructor:
|
||||
namespace: "myCache"
|
||||
|
||||
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.
|
||||
Cache objects are instantiated through a [CacheFactory](SilverStripe\Core\Cache\CacheFactory),
|
||||
which determines which cache adapter is used (see "Adapters" below for details).
|
||||
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.
|
||||
The returned object is of type `Zend_Cache`.
|
||||
Caches are namespaced, which might allow granular clearing of a particular cache without affecting others.
|
||||
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
|
||||
// foo is any name (try to be specific), and is used to get configuration
|
||||
// & storage info
|
||||
$cache = Cache::factory('foo');
|
||||
if (!($result = $cache->load($cachekey))) {
|
||||
$result = caluate some how;
|
||||
$cache->save($result, $cachekey);
|
||||
}
|
||||
return $result;
|
||||
use Psr\SimpleCache\CacheInterface
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
|
||||
|
||||
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.
|
||||
// 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
|
||||
}
|
||||
|
||||
## Invalidation
|
||||
|
||||
:::php
|
||||
// Disables all caches
|
||||
Cache::set_cache_lifetime('any', -1, 100);
|
||||
Caches can be invalidated in different ways. The easiest is to actively clear the
|
||||
entire cache. If the adapter supports namespaced cache clearing,
|
||||
this will only affect a subset of cache keys ("myCache" in this example):
|
||||
|
||||
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
|
||||
use Psr\SimpleCache\CacheInterface
|
||||
$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
|
||||
$cache = Cache::factory('foo');
|
||||
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
|
||||
:::php
|
||||
use Psr\SimpleCache\CacheInterface
|
||||
$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
|
||||
$cache = Cache::factory('foo');
|
||||
$cache->remove($cachekey);
|
||||
:::php
|
||||
use Psr\SimpleCache\CacheInterface
|
||||
$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,
|
||||
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.
|
||||
it often pays to increase the lifetime of caches.
|
||||
You can also set your lifetime to `0`, which means they won't expire.
|
||||
Since many adapters don't have a way to actively remove expired caches,
|
||||
you need to be careful with resources here (e.g. filesystem space).
|
||||
|
||||
:::php
|
||||
// set all caches to 3 hours
|
||||
Cache::set_cache_lifetime('any', 60*60*3);
|
||||
:::yml
|
||||
SilverStripe\Core\Injector\Injector:
|
||||
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.
|
||||
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.
|
||||
:::php
|
||||
use Psr\SimpleCache\CacheInterface
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
|
||||
|
||||
// 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
|
||||
any classes that implement the `Flushable` interface. Using this, you can trigger your caches to clean.
|
||||
## Adapters
|
||||
|
||||
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/)
|
||||
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.
|
||||
Since we're using dependency injection to create caches,
|
||||
you need to define a factory for a particular adapter,
|
||||
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
|
||||
// _config.php
|
||||
Cache::add_backend(
|
||||
'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);
|
||||
Example: Configure core caches to use [memcached](http://www.danga.com/memcached/),
|
||||
which requires the [memcached PHP extension](http://php.net/memcached),
|
||||
and takes a `MemcachedClient` instance as a constructor argument.
|
||||
|
||||
### 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)
|
||||
(Alternative PHP Cache) extension (which is of course need for using this backend).
|
||||
## Additional Caches
|
||||
|
||||
:::php
|
||||
Cache::add_backend('primary_apc', 'APC');
|
||||
Cache::pick_backend('primary_apc', 'any', 10);
|
||||
Unfortunately not all caches are configurable via cache adapters.
|
||||
|
||||
### 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
|
||||
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);
|
||||
* [SSViewer](api:SilverStripe\View\SSViewer) writes compiled templates as PHP files to the filesystem
|
||||
(in order to achieve opcode caching on `include()` calls)
|
||||
* [ConfigManifest](api:SilverStripe\Core\Manifest\ConfigManifest) is hardcoded to use `FilesystemCache`
|
||||
* [ClassManifest](api:SilverStripe\Core\Manifest\ClassManifest) and [ThemeManifest](api:SilverStripe\View\ThemeManifest)
|
||||
are using a custom `ManifestCache`
|
||||
* [i18n](api:SilverStripe\i18n\i18n) uses `Symfony\Component\Config\ConfigCacheFactoryInterface` (filesystem-based)
|
||||
|
@ -16,6 +16,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
|
||||
* [Filesystem API](#overview-filesystem)
|
||||
* [Template and Form API](#overview-template)
|
||||
* [i18n](#overview-i18n)
|
||||
* [Cache](#overview-cache)
|
||||
* [Email and Mailer](#overview-mailer)
|
||||
* [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
|
||||
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.
|
||||
* 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.
|
||||
|
||||
## <a name="upgrading"></a>Upgrading
|
||||
@ -1473,6 +1475,93 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
|
||||
* `i18n::get_common_locales()` 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-api"></a>Email Additions / Changes
|
||||
|
@ -4,12 +4,11 @@ namespace SilverStripe\Assets;
|
||||
|
||||
use SilverStripe\Assets\Storage\AssetContainer;
|
||||
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\Flushable;
|
||||
use InvalidArgumentException;
|
||||
use Zend_Cache;
|
||||
use Zend_Cache_Core;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @var Zend_Cache_Core
|
||||
* @var \Psr\SimpleCache\CacheInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
@ -66,7 +65,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
|
||||
public function __construct(AssetContainer $assetContainer = null)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->cache = Cache::factory('GDBackend_Manipulations');
|
||||
$this->cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
|
||||
|
||||
if ($assetContainer) {
|
||||
$this->loadFromContainer($assetContainer);
|
||||
@ -219,7 +218,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
|
||||
public function failedResample($arg = null)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
$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()
|
||||
{
|
||||
// Clear factory
|
||||
$cache = Cache::factory('GDBackend_Manipulations');
|
||||
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
|
||||
$cache->clear();
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
);
|
||||
}
|
||||
}
|
36
src/Core/Cache/ApcuCacheFactory.php
Normal file
36
src/Core/Cache/ApcuCacheFactory.php
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
20
src/Core/Cache/CacheFactory.php
Normal file
20
src/Core/Cache/CacheFactory.php
Normal 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());
|
||||
}
|
79
src/Core/Cache/DefaultCacheFactory.php
Normal file
79
src/Core/Cache/DefaultCacheFactory.php
Normal 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]]);
|
||||
}
|
||||
}
|
35
src/Core/Cache/FilesystemCacheFactory.php
Normal file
35
src/Core/Cache/FilesystemCacheFactory.php
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
36
src/Core/Cache/MemcachedCacheFactory.php
Normal file
36
src/Core/Cache/MemcachedCacheFactory.php
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
@ -54,14 +54,6 @@ mb_regex_encoding('UTF-8');
|
||||
*/
|
||||
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
|
||||
// subsequently used by some of the following code
|
||||
$injector = new Injector(array('locator' => 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator'));
|
||||
|
@ -7,10 +7,9 @@ use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\DAG;
|
||||
use SilverStripe\Core\Config\DAG_CyclicException;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
use Traversable;
|
||||
use Zend_Cache_Core;
|
||||
|
||||
/**
|
||||
* A utility class which builds a manifest of configuration items
|
||||
@ -28,7 +27,7 @@ class ConfigManifest
|
||||
protected $includeTests;
|
||||
|
||||
/**
|
||||
* @var Zend_Cache_Core
|
||||
* @var FilesystemCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
@ -114,15 +113,15 @@ class ConfigManifest
|
||||
$this->key = sha1($base).'_';
|
||||
$this->includeTests = $includeTests;
|
||||
|
||||
// Get the Zend Cache to load/store cache into
|
||||
// Get a cache singleton
|
||||
$this->cache = $this->getCache();
|
||||
|
||||
// Unless we're forcing regen, try loading from cache
|
||||
if (!$forceRegen) {
|
||||
// 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
|
||||
$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
|
||||
@ -136,14 +135,12 @@ class ConfigManifest
|
||||
|
||||
/**
|
||||
* Provides a hook for mock unit tests despite no DI
|
||||
* @return Zend_Cache_Core
|
||||
* @return \Psr\SimpleCache\CacheInterface
|
||||
*/
|
||||
protected function getCache()
|
||||
{
|
||||
return Cache::factory('SS_Configuration', 'Core', array(
|
||||
'automatic_serialization' => true,
|
||||
'lifetime' => null
|
||||
));
|
||||
// TODO Replace with CoreConfigCreator, see https://github.com/silverstripe/silverstripe-framework/pull/6641/files#diff-f8c9b17e06432278197a7d5c3a1043cb
|
||||
return new FilesystemCache('SS_Configuration', 0, getTempFolder());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,9 +261,9 @@ class ConfigManifest
|
||||
$this->buildVariantKeySpec();
|
||||
|
||||
if ($cache) {
|
||||
$this->cache->save($this->phpConfigSources, $this->key.'php_config_sources');
|
||||
$this->cache->save($this->yamlConfigFragments, $this->key.'yaml_config_fragments');
|
||||
$this->cache->save($this->variantKeySpec, $this->key.'variant_key_spec');
|
||||
$this->cache->set($this->key.'php_config_sources', $this->phpConfigSources);
|
||||
$this->cache->set($this->key.'yaml_config_fragments', $this->yamlConfigFragments);
|
||||
$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
|
||||
if (!$this->yamlConfigFragments) {
|
||||
// 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();
|
||||
return;
|
||||
} // Otherwise try and load the fragments so we can build the variant
|
||||
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) {
|
||||
$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
|
||||
|
@ -743,10 +743,10 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
// Get any 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'] .= $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'] .= '}';
|
||||
}
|
||||
|
||||
|
@ -4020,10 +4020,10 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
// Get any 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'] .= $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'] .= '}';
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ namespace SilverStripe\View;
|
||||
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Flushable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
@ -14,9 +14,6 @@ use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Security\Permission;
|
||||
use InvalidArgumentException;
|
||||
use Zend_Cache_Backend_ExtendedInterface;
|
||||
use Zend_Cache;
|
||||
use Zend_Cache_Core;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (!self::$cacheblock_cache_flushed || $force) {
|
||||
$cache = Cache::factory('cacheblock');
|
||||
$backend = $cache->getBackend();
|
||||
|
||||
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);
|
||||
}
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.cacheblock');
|
||||
$cache->clear();
|
||||
|
||||
|
||||
self::$cacheblock_cache_flushed = true;
|
||||
@ -484,14 +472,14 @@ class SSViewer implements Flushable
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Zend_Cache_Core
|
||||
* @var CacheInterface
|
||||
*/
|
||||
protected $partialCacheStore = null;
|
||||
|
||||
/**
|
||||
* Set the cache object to use when storing / retrieving partial cache blocks.
|
||||
*
|
||||
* @param Zend_Cache_Core $cache
|
||||
* @param CacheInterface $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.
|
||||
*
|
||||
* @return Zend_Cache_Core
|
||||
* @return CacheInterface
|
||||
*/
|
||||
public function getPartialCacheStore()
|
||||
{
|
||||
return $this->partialCacheStore ? $this->partialCacheStore : Cache::factory('cacheblock');
|
||||
return $this->partialCacheStore ? $this->partialCacheStore : Injector::inst()->get(CacheInterface::class . '.cacheblock');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,8 @@
|
||||
namespace SilverStripe\Assets\Tests;
|
||||
|
||||
use SilverStripe\Assets\GDBackend;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
|
||||
/**
|
||||
@ -192,9 +193,9 @@ class GDTest extends SapphireTest
|
||||
$gd->loadFrom($fullPath);
|
||||
|
||||
// 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))));
|
||||
$data = $cache->load($key);
|
||||
$data = $cache->get($key);
|
||||
$this->assertEquals('1', $data);
|
||||
}
|
||||
|
||||
|
@ -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'));
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Manifest\ConfigManifest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use ReflectionProperty;
|
||||
use Zend_Cache_Core;
|
||||
use Symfony\Component\Cache\Simple\ArrayCache;
|
||||
|
||||
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
|
||||
*
|
||||
* @return Zend_Cache_Core
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function getCacheMock()
|
||||
{
|
||||
return $this->getMock(
|
||||
'Zend_Cache_Core',
|
||||
array('load', 'save'),
|
||||
ArrayCache::class,
|
||||
array('set', 'get'),
|
||||
array(),
|
||||
'',
|
||||
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
|
||||
*
|
||||
* @param $methods
|
||||
* @return ConfigManifest
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function getManifestMock($methods)
|
||||
{
|
||||
@ -82,7 +82,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
// Set up a cache where we expect load to never be called
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->never())
|
||||
->method('load');
|
||||
->method('get');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
@ -95,7 +95,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->atLeastOnce())
|
||||
->method('save');
|
||||
->method('set');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
@ -119,7 +119,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
// Load should be called twice
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load');
|
||||
->method('get');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
@ -133,7 +133,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->method('get')
|
||||
->will($this->onConsecutiveCalls(false, false));
|
||||
|
||||
$manifest->expects($this->any())
|
||||
@ -151,7 +151,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->method('get')
|
||||
->will($this->onConsecutiveCalls(array(), array()));
|
||||
|
||||
$manifest->expects($this->any())
|
||||
@ -186,7 +186,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->will($this->returnValue(false))
|
||||
->method('load');
|
||||
->method('get');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
@ -204,7 +204,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($parameter) {
|
||||
if (strpos($parameter, 'variant_key_spec') !== false) {
|
||||
return false;
|
||||
@ -227,7 +227,7 @@ class ConfigManifestTest extends SapphireTest
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($parameter) {
|
||||
if (strpos($parameter, 'php_config_sources') !== false) {
|
||||
return false;
|
||||
|
@ -5,8 +5,8 @@ namespace SilverStripe\ORM\Tests;
|
||||
require_once __DIR__ . "/ImageTest.php";
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Zend_Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
class GDImageTest extends ImageTest
|
||||
{
|
||||
@ -32,8 +32,9 @@ class GDImageTest extends ImageTest
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$cache = Cache::factory('GDBackend_Manipulations');
|
||||
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
|
||||
$cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
|
||||
$cache->clear();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
namespace SilverStripe\View\Tests;
|
||||
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\Versioning\Versioned;
|
||||
use SilverStripe\Core\Cache;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Control\Director;
|
||||
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
|
||||
|
||||
@ -27,8 +30,15 @@ class SSViewerCacheBlockTest extends SapphireTest
|
||||
{
|
||||
$this->data = new SSViewerCacheBlockTest\TestModel();
|
||||
|
||||
Cache::factory('cacheblock')->clean();
|
||||
Cache::set_cache_lifetime('cacheblock', $cacheOn ? 600 : -1);
|
||||
$cache = null;
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user