Commit 8fcce5b3 authored by webchick's avatar webchick

Issue #2460911 by Wim Leers, jhodgdon: Search reindexing should invalidate cache tags

parent 4553018c
......@@ -174,6 +174,13 @@ public function isSearchExecutable() {
return !empty($this->keywords) || (isset($this->searchParameters['f']) && count($this->searchParameters['f']));
}
/**
* {@inheritdoc}
*/
public function getType() {
return $this->getPluginId();
}
/**
* {@inheritdoc}
*/
......
......@@ -8,6 +8,7 @@
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
......@@ -152,6 +153,15 @@ function search_index_clear($type = NULL, $sid = NULL, $langcode = NULL) {
$query_index->execute();
$query_dataset->execute();
if ($type) {
// Invalidate all render cache items that contain data from this index.
Cache::invalidateTags(['search_index:' . $type]);
}
else {
// Invalidate all render cache items that contain data from any index.
Cache::invalidateTags(['search_index']);
}
}
/**
......@@ -499,6 +509,8 @@ function search_index($type, $sid, $langcode, $text) {
$tag = !$tag;
}
// Remove the item $sid from the search index, and invalidate the relevant
// cache tags.
search_index_clear($type, $sid, $langcode);
// Insert cleaned up data into dataset
......
......@@ -7,6 +7,7 @@
namespace Drupal\search\Controller;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Controller\ControllerBase;
use Drupal\search\SearchPageInterface;
......@@ -127,6 +128,14 @@ public function view(Request $request, SearchPageInterface $entity) {
),
);
// If this plugin uses a search index, then also add the cache tag tracking
// that search index, so that cached search result pages are invalidated
// when necessary.
if ($plugin->getType()) {
$build['search_results']['#cache']['tags'][] = 'search_index';
$build['search_results']['#cache']['tags'][] = 'search_index:' . $plugin->getType();
}
$build['pager'] = array(
'#type' => 'pager',
);
......
......@@ -64,6 +64,18 @@ public function getAttributes();
*/
public function isSearchExecutable();
/**
* Returns the search index type this plugin uses.
*
* @return string|null
* The type used by this search plugin in the search index, or NULL if this
* plugin does not use the search index.
*
* @see search_index()
* @see search_index_clear()
*/
public function getType();
/**
* Executes the search.
*
......
......@@ -85,6 +85,13 @@ public function isSearchExecutable() {
return !empty($this->keywords);
}
/**
* {@inheritdoc}
*/
public function getType() {
return NULL;
}
/**
* {@inheritdoc}
*/
......
......@@ -13,6 +13,7 @@
* @group search
*/
class SearchPageCacheTagsTest extends SearchTestBase {
/**
* {@inheritdoc}
*/
......@@ -25,11 +26,33 @@ class SearchPageCacheTagsTest extends SearchTestBase {
*/
protected $searchingUser;
/**
* A node that is indexed by the search module.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Enable the page cache.
// @todo Remove in https://www.drupal.org/node/606840.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
// Create user.
$this->searchingUser = $this->drupalCreateUser(array('search content', 'access user profiles'));
// Create a node and update the search index.
$this->node = $this->drupalCreateNode(['title' => 'bike shed shop']);
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
}
/**
......@@ -40,26 +63,47 @@ function testSearchText() {
// Initial page for searching nodes.
$this->drupalGet('search/node');
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
$this->assertTrue(in_array('config:search.page.node_search', $cache_tags));
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index:node_search');
// Node search results.
$edit = array();
$edit['keys'] = 'bike shed';
$this->drupalPostForm('search/node', $edit, t('Search'));
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
$this->assertTrue(in_array('config:search.page.node_search', $cache_tags));
$this->assertText('bike shed shop');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
// Updating a node should invalidate the search plugin's index cache tag.
$this->node->title = 'bike shop';
$this->node->save();
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('bike shop');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
// Deleting a node should invalidate the search plugin's index cache tag.
$this->node->delete();
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('Your search yielded no results.');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
// Initial page for searching users.
$this->drupalGet('search/user');
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
$this->assertTrue(in_array('config:search.page.user_search', $cache_tags));
$this->assertCacheTag('config:search.page.user_search');
$this->assertNoCacheTag('search_index');
$this->assertNoCacheTag('search_index:user_search');
// User search results.
$edit['keys'] = $this->searchingUser->getUsername();
$this->drupalPostForm('search/user', $edit, t('Search'));
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
$this->assertTrue(in_array('config:search.page.user_search', $cache_tags));
$this->assertCacheTag('config:search.page.user_search');
$this->assertNoCacheTag('search_index');
$this->assertNoCacheTag('search_index:user_search');
}
}
......@@ -2762,4 +2762,15 @@ protected function assertCacheTag($expected_cache_tag) {
$this->assertTrue(in_array($expected_cache_tag, $cache_tags), "'" . $expected_cache_tag . "' is present in the X-Drupal-Cache-Tags header.");
}
/**
* Asserts whether an expected cache tag was absent in the last response.
*
* @param string $cache_tag
* The cache tag to check.
*/
protected function assertNoCacheTag($cache_tag) {
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
$this->assertFalse(in_array($cache_tag, $cache_tags), "'" . $cache_tag . "' is absent in the X-Drupal-Cache-Tags header.");
}
}
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