diff --git a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php index 09f1e0e..02611b0 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php @@ -9,6 +9,7 @@ use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; use Drupal\Component\Plugin\Discovery\DiscoveryInterface; +use Drupal\Core\Cache\CacheBackendInterface; /** * Enables static and persistent caching of discovered plugin definitions. @@ -30,6 +31,20 @@ class CacheDecorator implements CachedDiscoveryInterface { protected $cacheBin; /** + * The timestamp indicating when the definition list cache expires. + * + * @var int + */ + protected $cacheExpire; + + /** + * The cache tags associated with the definition list. + * + * @var array + */ + protected $cacheTags; + + /** * The plugin definitions of the decorated discovery class. * * @var array @@ -54,11 +69,18 @@ class CacheDecorator implements CachedDiscoveryInterface { * The cache identifier used for storage of the definition list. * @param string $cache_bin * The cache bin used for storage and retrieval of the definition list. + * @param int $cache_expire + * A Unix timestamp indicating that the definition list will be considered + * invalid after this time. + * @param array $cache_tags + * The cache tags associated with the definition list */ - public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bin = 'cache') { + public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bin = 'cache', $cache_expire = CacheBackendInterface::CACHE_PERMANENT, array $cache_tags = array()) { $this->decorated = $decorated; $this->cacheKey = $cache_key; $this->cacheBin = $cache_bin; + $this->cacheExpire = $cache_expire; + $this->cacheTags = $cache_tags; } /** @@ -124,7 +146,7 @@ protected function getCachedDefinitions() { */ protected function setCachedDefinitions($definitions) { if (isset($this->cacheKey)) { - cache($this->cacheBin)->set($this->cacheKey, $definitions); + cache($this->cacheBin)->set($this->cacheKey, $definitions, $this->cacheExpire, $this->cacheTags); } $this->definitions = $definitions; } @@ -145,4 +167,5 @@ public function clearCachedDefinitions() { public function __call($method, $args) { return call_user_func_array(array($this->decorated, $method), $args); } + } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php index f2fd0f7..fa63c23 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\PluginManagerBase; use Drupal\Component\Plugin\Factory\DefaultFactory; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; +use Drupal\Core\Plugin\Discovery\CacheDecorator; /** * Manages aggregator fetcher plugins. @@ -18,6 +19,7 @@ class FetcherManager extends PluginManagerBase { public function __construct() { $this->discovery = new AnnotatedClassDiscovery('aggregator', 'fetcher'); + $this->discovery = new CacheDecorator($this->discovery, 'aggregator_fetcher:' . language(LANGUAGE_TYPE_INTERFACE)->langcode); $this->factory = new DefaultFactory($this->discovery); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php new file mode 100644 index 0000000..697e170 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php @@ -0,0 +1,120 @@ + 'CacheDecoratorLanguage', + 'description' => 'Tests that the CacheDecorator stores definitions by language appropriately.', + 'group' => 'Plugin API', + ); + } + + public function setUp() { + // Manually setup German as an additional language. + parent::setUp(); + $this->languages = array('de'); + require_once DRUPAL_ROOT .'/core/includes/language.inc'; + $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme')); + $this->drupalLogin($admin_user); + $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'de'), t('Add language')); + // Add a default locale storage for all these tests. + $this->storage = locale_storage(); + + // Populate sample definitions. + $this->mockBlockExpectedDefinitions = array( + 'user_login' => array( + 'label' => 'User login', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserLoginBlock', + ), + 'menu:main_menu' => array( + 'label' => 'Main menu', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock', + ), + 'menu:navigation' => array( + 'label' => 'Navigation', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock', + ), + 'layout' => array( + 'label' => 'Layout', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock', + ), + 'layout:foo' => array( + 'label' => 'Layout Foo', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock', + ), + ); + } + + /** + * Check the translations of the cached plugin definitions. + */ + public function testCacheDecoratorLanguage() { + $languages = $this->languages; + // Visit our destination first to prime any relevant strings. + $this->drupalGet('plugin_definition_test'); + // Check for the expected block labels on the page. + foreach ($this->mockBlockExpectedDefinitions as $plugin_id => $definition) { + $this->assertText($definition['label']); + // Find the appropriate locales_source lid for the purposes of + // translating. + $results = db_select('locales_source', 'ls') + ->fields('ls') + ->condition('source', $definition['label']) + ->execute(); + foreach ($results as $result) { + if ($result->lid) { + // Provide a translation for each mock block label. + foreach ($this->languages as $langcode) { + $this->storage->createTranslation(array( + 'lid' => $result->lid, + 'language' => $langcode, + 'translation' => $langcode . ' ' . $definition['label'], + ))->save(); + } + } + } + } + foreach ($languages as $langcode) { + $url = $langcode . '/plugin_definition_test'; + // Foreach language visit the language specific version of the page again. + $this->drupalGet($url); + $cache = cache()->get('mock_block:' . $langcode); + debug($cache); + foreach ($this->mockBlockExpectedDefinitions as $plugin_id => $definition) { + // Find our provided translations. + $label = $langcode . ' ' . $definition['label']; + $this->assertText($label); + } + } + } + +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php new file mode 100644 index 0000000..7a3f635 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php @@ -0,0 +1,24 @@ +discovery = new CacheDecorator($this->discovery, 'mock_block:' . language(LANGUAGE_TYPE_INTERFACE)->langcode); + } +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php index 14484f5..fcf1824 100644 --- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php @@ -39,7 +39,7 @@ public function __construct() { // A simple plugin: the user login block. $this->discovery->setDefinition('user_login', array( - 'label' => 'User login', + 'label' => t('User login'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserLoginBlock', )); @@ -61,7 +61,7 @@ public function __construct() { // MockLayoutBlockDeriver class ensures that both the base plugin and the // derivatives are available to the system. $this->discovery->setDefinition('layout', array( - 'label' => 'Layout', + 'label' => t('Layout'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock', 'derivative' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlockDeriver', )); diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php index c654bd0..1bfe806 100644 --- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php @@ -46,7 +46,7 @@ public function getDerivativeDefinitions(array $base_plugin_definition) { // customized one, but in a real implementation, this would be fetched // from some config() object. 'foo' => array( - 'label' => 'Layout Foo', + 'label' => t('Layout Foo'), ) + $base_plugin_definition, ); diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php index aa84202..6b33d13 100644 --- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php @@ -41,10 +41,10 @@ public function getDerivativeDefinitions(array $base_plugin_definition) { // Drupal's configuration to find out which menus actually exist. $derivatives = array( 'main_menu' => array( - 'label' => 'Main menu', + 'label' => t('Main menu'), ) + $base_plugin_definition, 'navigation' => array( - 'label' => 'Navigation', + 'label' => t('Navigation'), ) + $base_plugin_definition, ); diff --git a/core/modules/system/tests/modules/plugin_test/plugin_test.module b/core/modules/system/tests/modules/plugin_test/plugin_test.module index 147e052..45e8568 100644 --- a/core/modules/system/tests/modules/plugin_test/plugin_test.module +++ b/core/modules/system/tests/modules/plugin_test/plugin_test.module @@ -14,3 +14,31 @@ function plugin_test_plugin_test_alter(&$definitions) { } $definitions['user_login']['altered_single'] = TRUE; } + +function plugin_test_menu() { + $items = array(); + $items['plugin_definition_test'] = array( + 'access callback' => TRUE, + 'page callback' => 'plugin_test_definitions', + ); + return $items; +} + +function plugin_test_definitions() { + $manager = new Drupal\plugin_test\Plugin\CachedMockBlockManager(); + $output = array(); + foreach($manager->getDefinitions() as $plugin_id => $definition) { + $results = db_select('locales_source', 'ls') + ->fields('ls') + ->condition('source', $definition['label']) + ->execute(); + foreach ($results as $result) { + drupal_set_message('
' . var_export($result->lid, TRUE) . '
'); + } + $output[$plugin_id] = array( + '#type' => 'markup', + '#markup' => $definition['label'], + ); + } + return $output; +} \ No newline at end of file