diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php index 0a1b6781a8e..08a187b6c6c 100644 --- a/core/modules/node/src/NodeViewsData.php +++ b/core/modules/node/src/NodeViewsData.php @@ -378,8 +378,9 @@ class NodeViewsData extends EntityViewsData { ); $data['node_search_dataset']['table']['join'] = array( - 'node_search_index' => array( + 'node_field_data' => array( 'left_field' => 'sid', + 'left_table' => 'node_search_index', 'field' => 'sid', 'table' => 'search_dataset', 'extra' => 'node_search_index.type = node_search_dataset.type AND node_search_index.langcode = node_search_dataset.langcode', diff --git a/core/modules/search/src/Plugin/views/argument/Search.php b/core/modules/search/src/Plugin/views/argument/Search.php index 3bcf208f808..2cafe481410 100644 --- a/core/modules/search/src/Plugin/views/argument/Search.php +++ b/core/modules/search/src/Plugin/views/argument/Search.php @@ -93,33 +93,22 @@ class Search extends ArgumentPluginBase { $join = Views::pluginManager('join')->createInstance('standard', $definition); $search_total = $this->query->addRelationship('search_total', $join, $search_index); - $this->search_score = $this->query->addField('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE)); + $this->search_score = $this->query->addField('', "$search_index.score * $search_total.count", 'score', array('function' => 'sum')); $search_condition->condition("$search_index.type", $this->searchType); - if (!$this->searchQuery->simple()) { - $search_dataset = $this->query->addTable('search_dataset'); - $conditions = $this->searchQuery->conditions(); - $condition_conditions =& $conditions->conditions(); - foreach ($condition_conditions as $key => &$condition) { - // Make sure we just look at real conditions. - if (is_numeric($key)) { - // Replace the conditions with the table alias of views. - $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition); - } + $search_dataset = $this->query->addTable('node_search_dataset'); + $conditions = $this->searchQuery->conditions(); + $condition_conditions =& $conditions->conditions(); + foreach ($condition_conditions as $key => &$condition) { + // Make sure we just look at real conditions. + if (is_numeric($key)) { + // Replace the conditions with the table alias of views. + $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition); } - $search_conditions =& $search_condition->conditions(); - $search_conditions = array_merge($search_conditions, $condition_conditions); - } - else { - // Stores each condition, so and/or on the filter level will still work. - $or = db_or(); - foreach ($words as $word) { - $or->condition("$search_index.word", $word); - } - - $search_condition->condition($or); } + $search_conditions =& $search_condition->conditions(); + $search_conditions = array_merge($search_conditions, $condition_conditions); $this->query->addWhere(0, $search_condition); $this->query->addGroupBy("$search_index.sid"); diff --git a/core/modules/search/src/Plugin/views/filter/Search.php b/core/modules/search/src/Plugin/views/filter/Search.php index c5665cbc7c8..69f53b76f03 100644 --- a/core/modules/search/src/Plugin/views/filter/Search.php +++ b/core/modules/search/src/Plugin/views/filter/Search.php @@ -169,32 +169,21 @@ class Search extends FilterPluginBase { $search_total = $this->query->addRelationship('search_total', $join, $search_index); - $this->search_score = $this->query->addField('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE)); + $this->search_score = $this->query->addField('', "$search_index.score * $search_total.count", 'score', array('function' => 'sum')); $search_condition->condition("$search_index.type", $this->searchType); - if (!$this->searchQuery->simple()) { - $search_dataset = $this->query->addTable('search_dataset'); - $conditions = $this->searchQuery->conditions(); - $condition_conditions =& $conditions->conditions(); - foreach ($condition_conditions as $key => &$condition) { - // Make sure we just look at real conditions. - if (is_numeric($key)) { - // Replace the conditions with the table alias of views. - $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition); - } + $search_dataset = $this->query->addTable('node_search_dataset'); + $conditions = $this->searchQuery->conditions(); + $condition_conditions =& $conditions->conditions(); + foreach ($condition_conditions as $key => &$condition) { + // Make sure we just look at real conditions. + if (is_numeric($key)) { + // Replace the conditions with the table alias of views. + $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition); } - $search_conditions =& $search_condition->conditions(); - $search_conditions = array_merge($search_conditions, $condition_conditions); - } - else { - // Stores each condition, so and/or on the filter level will still work. - $or = db_or(); - foreach ($words as $word) { - $or->condition("$search_index.word", $word); - } - - $search_condition->condition($or); } + $search_conditions =& $search_condition->conditions(); + $search_conditions = array_merge($search_conditions, $condition_conditions); $this->query->addWhere($this->options['group'], $search_condition); $this->query->addGroupBy("$search_index.sid"); diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php index 72cc5f9d548..a110af0f53b 100644 --- a/core/modules/views/src/Plugin/views/query/Sql.php +++ b/core/modules/views/src/Plugin/views/query/Sql.php @@ -722,7 +722,11 @@ class Sql extends QueryPluginBase { * alias be used. * @param $params * An array of parameters additional to the field that will control items - * such as aggregation functions and DISTINCT. + * such as aggregation functions and DISTINCT. Some values that are + * recognized: + * - function: An aggregation function to apply, such as SUM. + * - aggregate: Set to TRUE to indicate that this value should be + * aggregated in a GROUP BY. * * @return $name * The name that this field can be referred to as. Usually this is the alias. diff --git a/core/modules/views/src/Tests/SearchIntegrationTest.php b/core/modules/views/src/Tests/SearchIntegrationTest.php index 7307ce12337..0a75e3913b5 100644 --- a/core/modules/views/src/Tests/SearchIntegrationTest.php +++ b/core/modules/views/src/Tests/SearchIntegrationTest.php @@ -7,6 +7,8 @@ namespace Drupal\views\Tests; +use Drupal\Component\Utility\SafeMarkup; + /** * Tests search integration filters. * @@ -35,8 +37,9 @@ class SearchIntegrationTest extends ViewTestBase { // Create a content type. $type = $this->drupalCreateContentType(); - // Add two nodes, one containing the word "pizza" and the other - // with the word "sandwich". Make the second node link to the first. + // Add three nodes, one containing the word "pizza", one containing + // "sandwich", and one containing "cola is good with pizza". Make the + // second node link to the first. $node['title'] = 'pizza'; $node['body'] = array(array('value' => 'pizza')); $node['type'] = $type->id(); @@ -49,6 +52,11 @@ class SearchIntegrationTest extends ViewTestBase { $node['body'] = array(array('value' => 'sandwich with a link to first node')); $this->drupalCreateNode($node); + $node['title'] = 'cola'; + $node['body'] = array(array('value' => 'cola is good with pizza')); + $node['type'] = $type->id(); + $this->drupalCreateNode($node); + // Run cron so that the search index tables are updated. $this->cronRun(); @@ -58,17 +66,56 @@ class SearchIntegrationTest extends ViewTestBase { // Page with a keyword filter of 'pizza'. $this->drupalGet('test-filter'); - $this->assertLink('pizza', 0, 'Pizza page is on Filter page'); - $this->assertNoLink('sandwich', 'Sandwich page is not on Filter page'); + $this->assertLink('pizza'); + $this->assertNoLink('sandwich'); + $this->assertLink('cola'); - // Page with a keyword argument. + // Page with a keyword argument, various argument values. + // Verify that the correct nodes are shown, and only once. $this->drupalGet('test-arg/pizza'); - $this->assertLink('pizza', 0, 'Pizza page is on argument page'); - $this->assertNoLink('sandwich', 'Sandwich page is not on argument page'); + $this->assertOneLink('pizza'); + $this->assertNoLink('sandwich'); + $this->assertOneLink('cola'); $this->drupalGet('test-arg/sandwich'); - $this->assertNoLink('pizza', 'Pizza page is not on argument page'); - $this->assertLink('sandwich', 0, 'Sandwich page is on argument page'); + $this->assertNoLink('pizza'); + $this->assertOneLink('sandwich'); + $this->assertNoLink('cola'); + + $this->drupalGet('test-arg/pizza OR sandwich'); + $this->assertOneLink('pizza'); + $this->assertOneLink('sandwich'); + $this->assertOneLink('cola'); + + $this->drupalGet('test-arg/pizza sandwich OR cola'); + $this->assertNoLink('pizza'); + $this->assertNoLink('sandwich'); + $this->assertOneLink('cola'); + + $this->drupalGet('test-arg/cola pizza'); + $this->assertNoLink('pizza'); + $this->assertNoLink('sandwich'); + $this->assertOneLink('cola'); + + $this->drupalGet('test-arg/"cola is good"'); + $this->assertNoLink('pizza'); + $this->assertNoLink('sandwich'); + $this->assertOneLink('cola'); + } + + /** + * Asserts that exactly one link exists with the given text. + * + * @param string $label + * Link label to assert. + * + * @return bool + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertOneLink($label) { + $links = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => $label)); + $message = SafeMarkup::format('Link with label %label found once.', array('%label' => $label)); + return $this->assert(isset($links[0]) && !isset($links[1]), $message); } }