Commit 1d8a302a authored by catch's avatar catch

Issue #1211864 by Xano, Taz, Dave Reid: Add caching to \Drupal\Core\Utility\Token::getInfo().

parent 5cc27d94
...@@ -652,7 +652,7 @@ services: ...@@ -652,7 +652,7 @@ services:
arguments: ['@module_handler'] arguments: ['@module_handler']
token: token:
class: Drupal\Core\Utility\Token class: Drupal\Core\Utility\Token
arguments: ['@module_handler'] arguments: ['@module_handler', '@cache.discovery', '@language_manager']
batch.storage: batch.storage:
class: Drupal\Core\Batch\BatchStorage class: Drupal\Core\Batch\BatchStorage
arguments: ['@database'] arguments: ['@database']
......
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
namespace Drupal\Core\Utility; namespace Drupal\Core\Utility;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManagerInterface;
/** /**
* Drupal placeholder/token replacement system. * Drupal placeholder/token replacement system.
...@@ -54,10 +57,29 @@ ...@@ -54,10 +57,29 @@
*/ */
class Token { class Token {
/**
* The tag to cache token info with.
*/
const TOKEN_INFO_CACHE_TAG = 'token_info';
/**
* The token cache.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/** /**
* Token definitions. * Token definitions.
* *
* @var array|null * @var array[]|null
* An array of token definitions, or NULL when the definitions are not set. * An array of token definitions, or NULL when the definitions are not set.
* *
* @see self::setInfo() * @see self::setInfo()
...@@ -74,11 +96,18 @@ class Token { ...@@ -74,11 +96,18 @@ class Token {
protected $moduleHandler; protected $moduleHandler;
/** /**
* Constructor. * Constructs a new class instance.
* *
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The token cache.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/ */
public function __construct(ModuleHandlerInterface $module_handler) { public function __construct(ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager) {
$this->cache = $cache;
$this->languageManager = $language_manager;
$this->moduleHandler = $module_handler; $this->moduleHandler = $module_handler;
} }
...@@ -282,8 +311,18 @@ public function findWithPrefix(array $tokens, $prefix, $delimiter = ':') { ...@@ -282,8 +311,18 @@ public function findWithPrefix(array $tokens, $prefix, $delimiter = ':') {
*/ */
public function getInfo() { public function getInfo() {
if (is_null($this->tokenInfo)) { if (is_null($this->tokenInfo)) {
$this->tokenInfo = $this->moduleHandler->invokeAll('token_info'); $cache_id = 'token_info:' . $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id;
$this->moduleHandler->alter('token_info', $this->tokenInfo); $cache = $this->cache->get($cache_id);
if ($cache) {
$this->tokenInfo = $cache->data;
}
else {
$this->tokenInfo = $this->moduleHandler->invokeAll('token_info');
$this->moduleHandler->alter('token_info', $this->tokenInfo);
$this->cache->set($cache_id, $this->tokenInfo, CacheBackendInterface::CACHE_PERMANENT, array(
static::TOKEN_INFO_CACHE_TAG => TRUE,
));
}
} }
return $this->tokenInfo; return $this->tokenInfo;
...@@ -307,5 +346,8 @@ public function setInfo(array $tokens) { ...@@ -307,5 +346,8 @@ public function setInfo(array $tokens) {
*/ */
public function resetInfo() { public function resetInfo() {
$this->tokenInfo = NULL; $this->tokenInfo = NULL;
$this->cache->deleteTags(array(
static::TOKEN_INFO_CACHE_TAG => TRUE,
));
} }
} }
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Utility\TokenUnitTest.
*/
namespace Drupal\Tests\Core\Utility;
use Drupal\Core\Language\Language;
use Drupal\Core\Utility\Token;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Tests\Core\Utility\Token
*/
class TokenUnitTest extends UnitTestCase {
/**
* The cache used for testing.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cache;
/**
* The language manager used for testing.
*
* @var \Drupal\Core\Language\LanguageManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $languageManager;
/**
* The module handler service used for testing.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $moduleHandler;
/**
* The token service under test.
*
* @var \Drupal\Core\Utility\Token|\PHPUnit_Framework_MockObject_MockObject
*/
protected $token;
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'description' => '',
'name' => '\Drupal\Tests\Core\Utility\Token unit test',
'group' => 'System',
);
}
/**
* {@inheritdoc}
*/
public function setUp() {
$this->cache = $this->getMock('\Drupal\Core\Cache\CacheBackendInterface');
$this->languageManager = $this->getMockBuilder('\Drupal\Core\Language\LanguageManager')
->disableOriginalConstructor()
->getMock();
$this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
$this->token = new Token($this->moduleHandler, $this->cache, $this->languageManager);
}
/**
* @covers getInfo
*/
public function testGetInfo() {
$token_info = array(
'types' => array(
'foo' => array(
'name' => $this->randomName(),
),
),
);
$language = $this->getMock('\Drupal\Core\Language\Language');
$language->id = $this->randomName();
$this->languageManager->expects($this->once())
->method('getCurrentLanguage')
->with(Language::TYPE_CONTENT)
->will($this->returnValue($language));
// The persistent cache must only be hit once, after which the info is
// cached statically.
$this->cache->expects($this->once())
->method('get');
$this->cache->expects($this->once())
->method('set')
->with('token_info:' . $language->id, $token_info);
$this->moduleHandler->expects($this->once())
->method('invokeAll')
->with('token_info')
->will($this->returnValue($token_info));
$this->moduleHandler->expects($this->once())
->method('alter')
->with('token_info', $token_info);
// Get the information for the first time. The cache should be checked, the
// hooks invoked, and the info should be set to the cache should.
$this->token->getInfo();
// Get the information for the second time. The data must be returned from
// the static cache, so the persistent cache must not be accessed and the
// hooks must not be invoked.
$this->token->getInfo();
}
}
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