Commit 5639ae2d authored by catch's avatar catch

Issue #1167248 by Berdir, damiankloip, Alan Evans, beejeebus, catch: Add...

Issue #1167248 by Berdir, damiankloip, Alan Evans, beejeebus, catch: Add CacheBackendInterface::setMultiple().
parent a4127f24
...@@ -131,6 +131,15 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array ...@@ -131,6 +131,15 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array
} }
} }
/**
* {@inheritdoc}
*/
public function setMultiple(array $items) {
foreach ($this->backends as $backend) {
$backend->setMultiple($items);
}
}
/** /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete(). * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/ */
......
...@@ -95,6 +95,26 @@ public function getMultiple(&$cids, $allow_invalid = FALSE); ...@@ -95,6 +95,26 @@ public function getMultiple(&$cids, $allow_invalid = FALSE);
*/ */
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()); public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array());
/**
* Store multiple items in the persistent cache.
*
* @param array $items
* An array of cache items, keyed by cid. In the form:
* @code
* $items = array(
* $cid => array(
* // Required, will be automatically serialized if not a string.
* 'data' => $data,
* // Optional, defaults to CacheBackendInterface::CACHE_PERMANENT.
* 'expire' => CacheBackendInterface::CACHE_PERMANENT,
* // (optional) The cache tags for this item, see CacheBackendInterface::set().
* 'tags' => array(),
* ),
* );
* @endcode
*/
public function setMultiple(array $items);
/** /**
* Deletes an item from the cache. * Deletes an item from the cache.
* *
......
...@@ -201,6 +201,78 @@ protected function doSet($cid, $data, $expire, $tags) { ...@@ -201,6 +201,78 @@ protected function doSet($cid, $data, $expire, $tags) {
->execute(); ->execute();
} }
/**
* {@inheritdoc}
*/
public function setMultiple(array $items) {
$deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array());
$invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array());
// Use a transaction so that the database can write the changes in a single
// commit.
$transaction = $this->connection->startTransaction();
try {
// Delete all items first so we can do one insert. Rather than mulitple
// merge queries.
$this->deleteMultiple(array_keys($items));
$query = $this->connection
->insert($this->bin)
->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum_invalidations', 'checksum_deletions'));
foreach ($items as $cid => $item) {
$item += array(
'expire' => CacheBackendInterface::CACHE_PERMANENT,
'tags' => array(),
);
$flat_tags = $this->flattenTags($item['tags']);
// Remove tags that were already deleted or invalidated during this
// request from the static caches so that another deletion or
// invalidation can occur.
foreach ($flat_tags as $tag) {
if (isset($deleted_tags[$tag])) {
unset($deleted_tags[$tag]);
}
if (isset($invalidated_tags[$tag])) {
unset($invalidated_tags[$tag]);
}
}
$checksum = $this->checksumTags($flat_tags);
$fields = array(
'cid' => $cid,
'expire' => $item['expire'],
'created' => REQUEST_TIME,
'tags' => implode(' ', $flat_tags),
'checksum_invalidations' => $checksum['invalidations'],
'checksum_deletions' => $checksum['deletions'],
);
if (!is_string($item['data'])) {
$fields['data'] = serialize($item['data']);
$fields['serialized'] = 1;
}
else {
$fields['data'] = $item['data'];
$fields['serialized'] = 0;
}
$query->values($fields);
}
$query->execute();
}
catch (\Exception $e) {
$transaction->rollback();
// @todo Log something here or just re throw?
throw $e;
}
}
/** /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete(). * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/ */
......
...@@ -106,6 +106,15 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array ...@@ -106,6 +106,15 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array
); );
} }
/**
* {@inheritdoc}
*/
public function setMultiple(array $items = array()) {
foreach ($items as $cid => $item) {
$this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT, isset($item['tags']) ? $item['tags'] : array());
}
}
/** /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete(). * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/ */
...@@ -196,11 +205,11 @@ protected function flattenTags(array $tags) { ...@@ -196,11 +205,11 @@ protected function flattenTags(array $tags) {
foreach ($tags as $namespace => $values) { foreach ($tags as $namespace => $values) {
if (is_array($values)) { if (is_array($values)) {
foreach ($values as $value) { foreach ($values as $value) {
$flat_tags["$namespace:$value"] = "$namespace:$value"; $flat_tags[] = "$namespace:$value";
} }
} }
else { else {
$flat_tags["$namespace:$values"] = "$namespace:$values"; $flat_tags[] = "$namespace:$values";
} }
} }
return $flat_tags; return $flat_tags;
......
...@@ -49,6 +49,11 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { ...@@ -49,6 +49,11 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
*/ */
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {} public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {}
/**
* {@inheritdoc}
*/
public function setMultiple(array $items = array()) {}
/** /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete(). * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/ */
......
...@@ -93,9 +93,12 @@ public function readMultiple(array $names) { ...@@ -93,9 +93,12 @@ public function readMultiple(array $names) {
$list = $this->storage->readMultiple($names); $list = $this->storage->readMultiple($names);
// Cache configuration objects that were loaded from the storage, cache // Cache configuration objects that were loaded from the storage, cache
// missing configuration objects as an explicit FALSE. // missing configuration objects as an explicit FALSE.
$items = array();
foreach ($names as $name) { foreach ($names as $name) {
$this->cache->set($name, isset($list[$name]) ? $list[$name] : FALSE); $items[$name] = array('data' => isset($list[$name]) ? $list[$name] : FALSE);
} }
$this->cache->setMultiple($items);
} }
// Add the configuration objects from the cache to the list. // Add the configuration objects from the cache to the list.
......
...@@ -237,7 +237,7 @@ public function testBlockViewBuilderAlter() { ...@@ -237,7 +237,7 @@ public function testBlockViewBuilderAlter() {
$cache_entry = $this->container->get('cache.render')->get($cid); $cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache'); $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache');
$this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.'); $this->assertIdentical($cache_entry->tags, $expected_flattened_tags); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid); $this->container->get('cache.render')->delete($cid);
// Advanced: cached block, but an alter hook adds an additional cache tag. // Advanced: cached block, but an alter hook adds an additional cache tag.
...@@ -251,7 +251,7 @@ public function testBlockViewBuilderAlter() { ...@@ -251,7 +251,7 @@ public function testBlockViewBuilderAlter() {
$cache_entry = $this->container->get('cache.render')->get($cid); $cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache', $alter_add_tag . ':1'); $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache', $alter_add_tag . ':1');
$this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.'); $this->assertIdentical($cache_entry->tags, $expected_flattened_tags); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid); $this->container->get('cache.render')->delete($cid);
// Advanced: cached block, but an alter hook adds a #pre_render callback to // Advanced: cached block, but an alter hook adds a #pre_render callback to
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\system\Tests\Cache; namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\simpletest\DrupalUnitTestBase; use Drupal\simpletest\DrupalUnitTestBase;
/** /**
...@@ -295,6 +296,43 @@ public function testGetMultiple() { ...@@ -295,6 +296,43 @@ public function testGetMultiple() {
$this->assertFalse(in_array('test19', $cids), "Added cache id test19 is not in cids array."); $this->assertFalse(in_array('test19', $cids), "Added cache id test19 is not in cids array.");
} }
/**
* Tests \Drupal\Core\Cache\CacheBackendInterface::setMultiple().
*/
public function testSetMultiple() {
$backend = $this->getCacheBackend();
$future_expiration = REQUEST_TIME + 100;
// Set multiple testing keys.
$backend->set('cid_1', 'Some other value');
$items = array(
'cid_1' => array('data' => 1),
'cid_2' => array('data' => 2),
'cid_3' => array('data' => array(1, 2)),
'cid_4' => array('data' => 1, 'expire' => $future_expiration),
'cid_5' => array('data' => 1, 'tags' => array('test' => array('a', 'b'))),
);
$backend->setMultiple($items);
$cids = array_keys($items);
$cached = $backend->getMultiple($cids);
$this->assertEqual($cached['cid_1']->data, $items['cid_1']['data'], 'Over-written cache item set correctly.');
$this->assertEqual($cached['cid_1']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
$this->assertEqual($cached['cid_2']->data, $items['cid_2']['data'], 'New cache item set correctly.');
$this->assertEqual($cached['cid_2']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
$this->assertEqual($cached['cid_3']->data, $items['cid_3']['data'], 'New cache item with serialized data set correctly.');
$this->assertEqual($cached['cid_3']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
$this->assertEqual($cached['cid_4']->data, $items['cid_4']['data'], 'New cache item set correctly.');
$this->assertEqual($cached['cid_4']->expire, $future_expiration, 'Cache expiration has been correctly set.');
$this->assertEqual($cached['cid_5']->data, $items['cid_5']['data'], 'New cache item set correctly.');
$this->assertEqual($cached['cid_5']->tags, array('test:a', 'test:b'));
}
/** /**
* Tests Drupal\Core\Cache\CacheBackendInterface::isEmpty(). * Tests Drupal\Core\Cache\CacheBackendInterface::isEmpty().
*/ */
......
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