Commit 3d2c548b authored by Dries's avatar Dries

Issue #1764232 by yched, tim.plunkett: CacheDecorator provides no way to clear cached definitions.

parent 02a2a0e4
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface.
*/
namespace Drupal\Component\Plugin\Discovery;
/**
* Interface for discovery compenents holding a cache of plugin definitions.
*/
interface CachedDiscoveryInterface extends DiscoveryInterface {
/**
* Clears cached plugin definitions.
*/
public function clearCachedDefinitions();
}
......@@ -8,11 +8,12 @@
namespace Drupal\Component\Plugin;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
/**
* Base class for plugin managers.
*/
abstract class PluginManagerBase implements PluginManagerInterface {
abstract class PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
/**
* The object that discovers plugins managed by this manager.
......@@ -67,6 +68,15 @@ public function getDefinitions() {
return $definitions;
}
/**
* Implements \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface::clearCachedDefinitions().
*/
public function clearCachedDefinitions() {
if ($this->discovery instanceof CachedDiscoveryInterface) {
$this->discovery->clearCachedDefinitions();
}
}
/**
* Implements Drupal\Component\Plugin\PluginManagerInterface::createInstance().
*/
......
......@@ -7,12 +7,13 @@
namespace Drupal\Core\Plugin\Discovery;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Enables static and persistent caching of discovered plugin definitions.
*/
class CacheDecorator implements DiscoveryInterface {
class CacheDecorator implements CachedDiscoveryInterface {
/**
* The cache key used to store the definition list.
......@@ -109,6 +110,16 @@ protected function setCachedDefinitions($definitions) {
$this->definitions = $definitions;
}
/**
* Implements \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface::clearCachedDefinitions().
*/
public function clearCachedDefinitions() {
if (isset($this->cacheKey)) {
cache($this->cacheBin)->delete($this->cacheKey);
}
$this->definitions = NULL;
}
/**
* Passes through all unknown calls onto the decorated object.
*/
......
......@@ -26,41 +26,18 @@ class FormatterPluginManager extends PluginManagerBase {
'default_value' => TRUE,
);
/**
* The cache bin used for plugin definitions.
*
* @var string
*/
protected $cache_bin = 'field';
/**
* The cache id used for plugin definitions.
*
* @var string
*/
protected $cache_id = 'field_formatter_types';
/**
* Constructs a FormatterPluginManager object.
*/
public function __construct() {
$this->baseDiscovery = new AlterDecorator(new FormatterLegacyDiscoveryDecorator(new AnnotatedClassDiscovery('field', 'formatter')), 'field_formatter_info');
$this->discovery = new CacheDecorator($this->baseDiscovery, $this->cache_id, $this->cache_bin);
$this->discovery = new AnnotatedClassDiscovery('field', 'formatter');
$this->discovery = new FormatterLegacyDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'field_formatter_info');
$this->discovery = new CacheDecorator($this->discovery, 'field_formatter_types', 'field');
$this->factory = new FormatterFactory($this);
}
/**
* Clears cached definitions.
*
* @todo Remove when http://drupal.org/node/1764232 is fixed.
*/
public function clearDefinitions() {
// Clear 'static' data by creating a new object.
$this->discovery = new CacheDecorator($this->baseDiscovery, $this->cache_id, $this->cache_bin);
cache($this->cache_bin)->delete($this->cache_id);
}
/**
* Overrides PluginManagerBase::getInstance().
*/
......
......@@ -27,41 +27,18 @@ class WidgetPluginManager extends PluginManagerBase {
'default_value' => TRUE,
);
/**
* The cache bin used for plugin definitions.
*
* @var string
*/
protected $cache_bin = 'field';
/**
* The cache id used for plugin definitions.
*
* @var string
*/
protected $cache_id = 'field_widget_types';
/**
* Constructs a WidgetPluginManager object.
*/
public function __construct() {
$this->baseDiscovery = new AlterDecorator(new WidgetLegacyDiscoveryDecorator(new AnnotatedClassDiscovery('field', 'widget')), 'field_widget_info');
$this->discovery = new CacheDecorator($this->baseDiscovery, $this->cache_id, $this->cache_bin);
$this->discovery = new AnnotatedClassDiscovery('field', 'widget');
$this->discovery = new WidgetLegacyDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'field_widget_info');
$this->discovery = new CacheDecorator($this->discovery, 'field_widget_types', 'field');
$this->factory = new WidgetFactory($this);
}
/**
* Clears cached definitions.
*
* @todo Remove when http://drupal.org/node/1764232 is fixed.
*/
public function clearDefinitions() {
// Clear 'static' data by creating a new object.
$this->discovery = new CacheDecorator($this->baseDiscovery, $this->cache_id, $this->cache_bin);
cache($this->cache_bin)->delete($this->cache_id);
}
/**
* Overrides Drupal\Component\Plugin\PluginManagerBase::getInstance().
*/
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Plugin\CacheDecoratorTest.
*/
namespace Drupal\system\Tests\Plugin;
use Drupal\system\Tests\Plugin\Discovery\DiscoveryTestBase;
use Drupal\Component\Plugin\Discovery\StaticDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
/**
* Tests \Drupal\Core\Plugin\Discovery\CacheDecorator behavior.
*/
class CacheDecoratorTest extends DiscoveryTestBase {
/**
* The cache bin.
*
* @var string
*/
protected $cacheBin = 'test_cacheDecorator';
/**
* The cache key.
*
* @var string
*/
protected $cacheKey = 'test_cacheDecorator';
public static function getInfo() {
return array(
'name' => 'CacheDecorator',
'description' => 'Tests the CacheDecorator.',
'group' => 'Plugin API',
);
}
public function setUp() {
global $conf;
parent::setUp();
// Use a non-db cache backend, so that we can use DiscoveryTestBase (which
// extends UnitTestBase).
$conf['cache_classes'][$this->cacheBin] = 'Drupal\Core\Cache\MemoryBackend';
// Create discovery objects to test.
$this->emptyDiscovery = new StaticDiscovery();
$this->emptyDiscovery = new CacheDecorator($this->emptyDiscovery, $this->cacheKey . '_empty', $this->cacheBin);
$this->discovery = new StaticDiscovery();
$this->discovery = new CacheDecorator($this->discovery, $this->cacheKey, $this->cacheBin);
// Populate sample definitions.
$this->expectedDefinitions = array(
'apple' => array(
'label' => 'Apple',
'color' => 'green',
),
'cherry' => array(
'label' => 'Cherry',
'color' => 'red',
),
'orange' => array(
'label' => 'Orange',
'color' => 'orange',
),
);
foreach ($this->expectedDefinitions as $plugin_id => $definition) {
$this->discovery->setDefinition($plugin_id, $definition);
}
}
/**
* Tests that discovered definitions are properly cached.
*
* This comes in addition to DiscoveryTestBase::testDiscoveryInterface(),
* that test the basic discovery behavior.
*/
public function testCachedDefinitions() {
$cache = cache($this->cacheBin);
// Check that nothing is cached initially.
$cached = $cache->get($this->cacheKey);
$this->assertIdentical($cached, FALSE, 'Cache is empty.');
// Get the definitions once, and check that they are present in the cache.
$definitions = $this->discovery->getDefinitions();
$this->assertIdentical($definitions, $this->expectedDefinitions, 'Definitions are correctly retrieved.');
$cached = $cache->get($this->cacheKey);
$this->assertIdentical($cached->data, $this->expectedDefinitions, 'Definitions are cached.');
// Check that the definitions are also cached in memory. Since the
// CacheDecorator::definitions property is protected, this is tested "from
// the outside" by wiping the cache entry, getting the definitions, and
// checking that the cache entry was not regenerated (thus showing that
// defintions were not fetched from the decorated discovery).
$cache->delete($this->cacheKey);
$definitions = $this->discovery->getDefinitions();
$cached = $cache->get($this->cacheKey);
$this->assertIdentical($cached, FALSE, 'Cache is empty.');
$this->assertIdentical($definitions, $this->expectedDefinitions, 'Definitions are cached in memory.');
}
/**
* Tests CacheDecorator::clearCachedDefinitions().
*/
public function testClearCachedDefinitions() {
$cache = cache($this->cacheBin);
// Populate the caches by collecting definitions once.
$this->discovery->getDefinitions();
// Add a new definition.
$this->expectedDefinitions['banana'] = array(
'label' => 'Banana',
'color' => 'yellow',
);
$this->discovery->setDefinition('banana', $this->expectedDefinitions['banana']);
// Check that the new definition is not found.
$definition = $this->discovery->getDefinition('banana');
$this->assertNull($definition, 'Newly added definition is not found.');
// Clear cached definitions, and check that the new definition is found.
$this->discovery->clearCachedDefinitions();
$cached = $cache->get($this->cacheKey);
$this->assertIdentical($cached, FALSE, 'Cache is empty.');
$definitions = $this->discovery->getDefinitions();
$this->assertIdentical($definitions, $this->expectedDefinitions, 'Newly added definition is found.');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment