Issue #1853536 by jhodgdon, dawehner, damiankloip, xjm, mgifford: Reintroduce Views integration for search.module (not supporting backlinks view).
parent
42e1b3a0ac
commit
54f8683de8
|
@ -619,6 +619,81 @@ function node_views_data() {
|
|||
),
|
||||
);
|
||||
|
||||
// Add search table, fields, filters, etc., but only if a page using the
|
||||
// node_search plugin is enabled.
|
||||
if (\Drupal::moduleHandler()->moduleExists('search')) {
|
||||
$enabled = FALSE;
|
||||
$search_page_repository = \Drupal::service('search.search_page_repository');
|
||||
foreach ($search_page_repository->getActiveSearchpages() as $page) {
|
||||
if ($page->getPlugin()->getPluginId() == 'node_search') {
|
||||
$enabled = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($enabled) {
|
||||
$data['node_search_index']['table']['group'] = t('Search');
|
||||
|
||||
// Automatically join to the node table. Use a Views table alias to
|
||||
// allow other modules to use this table too, if they use the search
|
||||
// index.
|
||||
$data['node_search_index']['table']['join'] = array(
|
||||
'node' => array(
|
||||
'left_field' => 'nid',
|
||||
'field' => 'sid',
|
||||
'table' => 'search_index',
|
||||
'extra' => "node_search_index.type = 'node_search'",
|
||||
)
|
||||
);
|
||||
|
||||
$data['node_search_total']['table']['join'] = array(
|
||||
'node_search_index' => array(
|
||||
'left_field' => 'word',
|
||||
'field' => 'word',
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_search_dataset']['table']['join'] = array(
|
||||
'node_search_index' => array(
|
||||
'left_field' => 'sid',
|
||||
'field' => 'sid',
|
||||
'extra' => 'node_search_index.type = node_search_dataset.type',
|
||||
'type' => 'INNER',
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_search_index']['score'] = array(
|
||||
'title' => t('Score'),
|
||||
'help' => t('The score of the search item. This will not be used if the search filter is not also present.'),
|
||||
'field' => array(
|
||||
'id' => 'search_score',
|
||||
'float' => TRUE,
|
||||
'no group by' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'search_score',
|
||||
'no group by' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_search_index']['keys'] = array(
|
||||
'title' => t('Search Keywords'),
|
||||
'help' => t('The keywords to search for.'),
|
||||
'filter' => array(
|
||||
'id' => 'search_keywords',
|
||||
'no group by' => TRUE,
|
||||
'search_type' => 'node_search',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'search',
|
||||
'no group by' => TRUE,
|
||||
'search_type' => 'node_search',
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
namespace Drupal\search\Plugin\views\argument;
|
||||
|
||||
use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Argument that accepts query keys for search.
|
||||
* Argument handler for search keywords.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
|
@ -19,30 +22,53 @@ use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
|
|||
class Search extends ArgumentPluginBase {
|
||||
|
||||
/**
|
||||
* Make sure that parseSearchExpression is run and everything is set up.
|
||||
* A search query to use for parsing search keywords.
|
||||
*
|
||||
* @param $input
|
||||
* The search phrase which was input by the user.
|
||||
* @var \Drupal\search\ViewsSearchQuery
|
||||
*/
|
||||
function query_parse_search_expression($input) {
|
||||
if (!isset($this->search_query)) {
|
||||
$this->search_query = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
|
||||
$this->search_query->searchExpression($input, $this->view->base_table);
|
||||
$this->search_query->publicParseSearchExpression();
|
||||
protected $searchQuery = NULL;
|
||||
|
||||
/**
|
||||
* The search type name (value of {search_index}.type in the database).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $searchType;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$this->searchType = $this->definition['search_type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up and parses the search query.
|
||||
*
|
||||
* @param string $input
|
||||
* The search keywords entered by the user.
|
||||
*/
|
||||
protected function queryParseSearchExpression($input) {
|
||||
if (!isset($this->searchQuery)) {
|
||||
$this->searchQuery = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
|
||||
$this->searchQuery->searchExpression($input, $this->searchType);
|
||||
$this->searchQuery->publicParseSearchExpression();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this argument to the query.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
$required = FALSE;
|
||||
$this->query_parse_search_expression($this->argument);
|
||||
if (!isset($this->search_query)) {
|
||||
$this->queryParseSearchExpression($this->argument);
|
||||
if (!isset($this->searchQuery)) {
|
||||
$required = TRUE;
|
||||
}
|
||||
else {
|
||||
$words = $this->search_query->words();
|
||||
$words = $this->searchQuery->words();
|
||||
if (empty($words)) {
|
||||
$required = TRUE;
|
||||
}
|
||||
|
@ -64,28 +90,22 @@ class Search extends ArgumentPluginBase {
|
|||
'left_table' => $search_index,
|
||||
'left_field' => 'word',
|
||||
);
|
||||
$join = \Drupal::service()->get('plugin.manager.views.join')->createInstance('standard', $definition);
|
||||
$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));
|
||||
|
||||
if (empty($this->query->relationships[$this->relationship])) {
|
||||
$base_table = $this->view->storage->get('base_table');
|
||||
}
|
||||
else {
|
||||
$base_table = $this->query->relationships[$this->relationship]['base'];
|
||||
}
|
||||
$search_condition->condition("$search_index.type", $base_table);
|
||||
$search_condition->condition("$search_index.type", $this->searchType);
|
||||
|
||||
if (!$this->search_query->simple()) {
|
||||
if (!$this->searchQuery->simple()) {
|
||||
$search_dataset = $this->query->addTable('search_dataset');
|
||||
$conditions = $this->search_query->conditions();
|
||||
$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->search_query->condition_replace_string('d.', "$search_dataset.", $condition);
|
||||
$this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition);
|
||||
}
|
||||
}
|
||||
$search_conditions =& $search_condition->conditions();
|
||||
|
@ -103,10 +123,14 @@ class Search extends ArgumentPluginBase {
|
|||
|
||||
$this->query->addWhere(0, $search_condition);
|
||||
$this->query->addGroupBy("$search_index.sid");
|
||||
$matches = $this->search_query->matches();
|
||||
$matches = $this->searchQuery->matches();
|
||||
$placeholder = $this->placeholder();
|
||||
$this->query->addHavingExpression(0, "COUNT(*) >= $placeholder", array($placeholder => $matches));
|
||||
}
|
||||
|
||||
// Set to NULL to prevent PDO exception when views object is cached
|
||||
// and to clear out memory.
|
||||
$this->searchQuery = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use Drupal\views\Plugin\views\field\Numeric;
|
|||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Field handler to provide simple renderer that allows linking to a node.
|
||||
* Field handler for search score.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
|
@ -19,50 +19,16 @@ use Drupal\views\ResultRow;
|
|||
*/
|
||||
class Score extends Numeric {
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$options['alternate_sort'] = array('default' => '');
|
||||
$options['alternate_order'] = array('default' => 'asc');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, &$form_state) {
|
||||
$style_options = $this->view->display_handler->getOption('style_options');
|
||||
if (isset($style_options['default']) && $style_options['default'] == $this->options['id']) {
|
||||
$handlers = $this->view->display_handler->getHandlers('field');
|
||||
$options = array('' => t('No alternate'));
|
||||
foreach ($handlers as $id => $handler) {
|
||||
$options[$id] = $handler->adminLabel();
|
||||
}
|
||||
|
||||
$form['alternate_sort'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Alternative sort'),
|
||||
'#description' => t('Pick an alternative default table sort field to use when the search score field is unavailable.'),
|
||||
'#options' => $options,
|
||||
'#default_value' => $this->options['alternate_sort'],
|
||||
);
|
||||
|
||||
$form['alternate_order'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Alternate sort order'),
|
||||
'#options' => array('asc' => t('Ascending'), 'desc' => t('Descending')),
|
||||
'#default_value' => $this->options['alternate_order'],
|
||||
);
|
||||
}
|
||||
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Check to see if the search filter added 'score' to the table.
|
||||
// Our filter stores it as $handler->search_score -- and we also
|
||||
// need to check its relationship to make sure that we're using the same
|
||||
// one or obviously this won't work.
|
||||
foreach ($this->view->filter as $handler) {
|
||||
if (isset($handler->search_score) && $handler->relationship == $this->relationship) {
|
||||
if (isset($handler->search_score) && ($handler->relationship == $this->relationship)) {
|
||||
$this->field_alias = $handler->search_score;
|
||||
$this->tableAlias = $handler->tableAlias;
|
||||
return;
|
||||
|
@ -71,13 +37,6 @@ class Score extends Numeric {
|
|||
|
||||
// Hide this field if no search filter is in place.
|
||||
$this->options['exclude'] = TRUE;
|
||||
if (!empty($this->options['alternate_sort'])) {
|
||||
if (isset($this->view->style_plugin->options['default']) && $this->view->style_plugin->options['default'] == $this->options['id']) {
|
||||
// Since the style handler initiates fields, we plug these values right into the active handler.
|
||||
$this->view->style_plugin->options['default'] = $this->options['alternate_sort'];
|
||||
$this->view->style_plugin->options['order'] = $this->options['alternate_order'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,5 +48,4 @@ class Score extends Numeric {
|
|||
return parent::render($values);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,35 +7,58 @@
|
|||
|
||||
namespace Drupal\search\Plugin\views\filter;
|
||||
|
||||
use Drupal\search\SearchQuery;
|
||||
use Drupal\views\Plugin\views\filter\FilterPluginBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Field handler to provide simple renderer that allows linking to a node.
|
||||
* Filter handler for search keywords.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @PluginID("search")
|
||||
* @PluginID("search_keywords")
|
||||
*/
|
||||
class Search extends FilterPluginBase {
|
||||
|
||||
/**
|
||||
* This filter is always considered multiple-valued.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $alwaysMultiple = TRUE;
|
||||
|
||||
/**
|
||||
* Stores an extended query extender from the search module.
|
||||
*
|
||||
* This value extends the query extender to be able to provide methods
|
||||
* which returns the protected values.
|
||||
*
|
||||
* @var \Drupal\search\ViewsSearchQuery
|
||||
*/
|
||||
var $search_query = NULL;
|
||||
* A search query to use for parsing search keywords.
|
||||
*
|
||||
* @var \Drupal\search\ViewsSearchQuery
|
||||
*/
|
||||
protected $searchQuery = NULL;
|
||||
|
||||
/**
|
||||
* Checks if the search query has been parsed.
|
||||
* TRUE if the search query has been parsed.
|
||||
*/
|
||||
var $parsed = FALSE;
|
||||
protected $parsed = FALSE;
|
||||
|
||||
/**
|
||||
* The search type name (value of {search_index}.type in the database).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $searchType;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$this->searchType = $this->definition['search_type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
|
@ -45,7 +68,7 @@ class Search extends FilterPluginBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Provide simple equality operator
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function operatorForm(&$form, &$form_state) {
|
||||
$form['operator'] = array(
|
||||
|
@ -53,27 +76,27 @@ class Search extends FilterPluginBase {
|
|||
'#title' => t('On empty input'),
|
||||
'#default_value' => $this->operator,
|
||||
'#options' => array(
|
||||
'optional' => t('Show All'),
|
||||
'required' => t('Show None'),
|
||||
'optional' => $this->t('Show All'),
|
||||
'required' => $this->t('Show None'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a simple textfield for equality
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function valueForm(&$form, &$form_state) {
|
||||
$form['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 15,
|
||||
'#default_value' => $this->value,
|
||||
'#attributes' => array('title' => t('Enter the terms you wish to search for.')),
|
||||
'#title' => empty($form_state['exposed']) ? t('Value') : '',
|
||||
'#attributes' => array('title' => $this->t('Search keywords')),
|
||||
'#title' => empty($form_state['exposed']) ? $this->t('Keywords') : '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateExposed(&$form, &$form_state) {
|
||||
if (!isset($this->options['expose']['identifier'])) {
|
||||
|
@ -82,47 +105,43 @@ class Search extends FilterPluginBase {
|
|||
|
||||
$key = $this->options['expose']['identifier'];
|
||||
if (!empty($form_state['values'][$key])) {
|
||||
$this->query_parse_search_expression($form_state['values'][$key]);
|
||||
if (count($this->search_query->words()) == 0) {
|
||||
$this->queryParseSearchExpression($form_state['values'][$key]);
|
||||
if (count($this->searchQuery->words()) == 0) {
|
||||
form_set_error($key, $form_state, format_plural(\Drupal::config('search.settings')->get('index.minimum_word_size'), 'You must include at least one positive keyword with 1 character or more.', 'You must include at least one positive keyword with @count characters or more.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that parseSearchExpression is run and everything is set up.
|
||||
* Sets up and parses the search query.
|
||||
*
|
||||
* @param $input
|
||||
* The search phrase which was input by the user.
|
||||
* @param string $input
|
||||
* The search keywords entered by the user.
|
||||
*/
|
||||
function query_parse_search_expression($input) {
|
||||
if (!isset($this->search_query)) {
|
||||
protected function queryParseSearchExpression($input) {
|
||||
if (!isset($this->searchQuery)) {
|
||||
$this->parsed = TRUE;
|
||||
$this->search_query = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
|
||||
$this->search_query->searchExpression($input, $this->view->base_table);
|
||||
$this->search_query->publicParseSearchExpression();
|
||||
$this->searchQuery = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
|
||||
$this->searchQuery->searchExpression($input, $this->searchType);
|
||||
$this->searchQuery->publicParseSearchExpression();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this filter to the query.
|
||||
*
|
||||
* Due to the nature of fapi, the value and the operator have an unintended
|
||||
* level of indirection. You will find them in $this->operator
|
||||
* and $this->value respectively.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Since attachment views don't validate the exposed input, parse the search
|
||||
// expression if required.
|
||||
if (!$this->parsed) {
|
||||
$this->query_parse_search_expression($this->value);
|
||||
$this->queryParseSearchExpression($this->value);
|
||||
}
|
||||
$required = FALSE;
|
||||
if (!isset($this->search_query)) {
|
||||
if (!isset($this->searchQuery)) {
|
||||
$required = TRUE;
|
||||
}
|
||||
else {
|
||||
$words = $this->search_query->words();
|
||||
$words = $this->searchQuery->words();
|
||||
if (empty($words)) {
|
||||
$required = TRUE;
|
||||
}
|
||||
|
@ -137,35 +156,30 @@ class Search extends FilterPluginBase {
|
|||
|
||||
$search_condition = db_and();
|
||||
|
||||
// Create a new join to relate the 'serach_total' table to our current 'search_index' table.
|
||||
// Create a new join to relate the 'search_total' table to our current
|
||||
// 'search_index' table.
|
||||
$definition = array(
|
||||
'table' => 'search_total',
|
||||
'field' => 'word',
|
||||
'left_table' => $search_index,
|
||||
'left_field' => 'word',
|
||||
);
|
||||
$join = \Drupal::service()->get('plugin.manager.views.join')->createInstance('standard', $definition);
|
||||
$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));
|
||||
|
||||
if (empty($this->query->relationships[$this->relationship])) {
|
||||
$base_table = $this->view->storage->get('base_table');
|
||||
}
|
||||
else {
|
||||
$base_table = $this->query->relationships[$this->relationship]['base'];
|
||||
}
|
||||
$search_condition->condition("$search_index.type", $base_table);
|
||||
if (!$this->search_query->simple()) {
|
||||
$search_condition->condition("$search_index.type", $this->searchType);
|
||||
if (!$this->searchQuery->simple()) {
|
||||
$search_dataset = $this->query->addTable('search_dataset');
|
||||
$conditions = $this->search_query->conditions();
|
||||
$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->search_query->condition_replace_string('d.', "$search_dataset.", $condition);
|
||||
$this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition);
|
||||
}
|
||||
}
|
||||
$search_conditions =& $search_condition->conditions();
|
||||
|
@ -183,12 +197,12 @@ class Search extends FilterPluginBase {
|
|||
|
||||
$this->query->addWhere($this->options['group'], $search_condition);
|
||||
$this->query->addGroupBy("$search_index.sid");
|
||||
$matches = $this->search_query->matches();
|
||||
$matches = $this->searchQuery->matches();
|
||||
$placeholder = $this->placeholder();
|
||||
$this->query->addHavingExpression($this->options['group'], "COUNT(*) >= $placeholder", array($placeholder => $matches));
|
||||
}
|
||||
// Set to NULL to prevent PDO exception when views object is cached.
|
||||
$this->search_query = NULL;
|
||||
$this->searchQuery = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,16 +10,19 @@ namespace Drupal\search\Plugin\views\row;
|
|||
use Drupal\views\Plugin\views\row\RowPluginBase;
|
||||
|
||||
/**
|
||||
* Plugin which performs a node_view on the resulting object.
|
||||
* Row handler plugin for displaying search results.
|
||||
*
|
||||
* @ViewsRow(
|
||||
* id = "search_view",
|
||||
* title = @Translation("Search"),
|
||||
* title = @Translation("Search results"),
|
||||
* help = @Translation("Provides a row plugin to display search results.")
|
||||
* )
|
||||
*/
|
||||
class SearchRow extends RowPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
|
@ -28,6 +31,9 @@ class SearchRow extends RowPluginBase {
|
|||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, &$form_state) {
|
||||
$form['score'] = array(
|
||||
'#type' => 'checkbox',
|
||||
|
@ -37,7 +43,7 @@ class SearchRow extends RowPluginBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Override the behavior of the render() function.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render($row) {
|
||||
return array(
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Drupal\search\Plugin\views\sort;
|
|||
use Drupal\views\Plugin\views\sort\SortPluginBase;
|
||||
|
||||
/**
|
||||
* Field handler to provide simple renderer that allows linking to a node.
|
||||
* Sort handler for sorting by search score.
|
||||
*
|
||||
* @ingroup views_sort_handlers
|
||||
*
|
||||
|
@ -18,6 +18,9 @@ use Drupal\views\Plugin\views\sort\SortPluginBase;
|
|||
*/
|
||||
class Score extends SortPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Check to see if the search filter/argument added 'score' to the table.
|
||||
// Our filter stores it as $handler->search_score -- and we also
|
||||
|
@ -33,8 +36,8 @@ class Score extends SortPluginBase {
|
|||
}
|
||||
}
|
||||
|
||||
// Do absolutely nothing if there is no filter/argument in place; there is no reason to
|
||||
// sort on the raw scores with this handler.
|
||||
// Do nothing if there is no filter/argument in place. There is no way
|
||||
// to sort on scores.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Drupal\search;
|
|||
use Drupal\Core\Database\Query\Condition;
|
||||
|
||||
/**
|
||||
* Extends the core SearchQuery to be able to gets it's protected values.
|
||||
* Extends the core SearchQuery to be able to gets its protected values.
|
||||
*/
|
||||
class ViewsSearchQuery extends SearchQuery {
|
||||
|
||||
|
@ -67,14 +67,14 @@ class ViewsSearchQuery extends SearchQuery {
|
|||
* @param \Drupal\Core\Database\Query\Condition $condition
|
||||
* The query condition in which the string is replaced.
|
||||
*/
|
||||
function condition_replace_string($search, $replace, &$condition) {
|
||||
function conditionReplaceString($search, $replace, &$condition) {
|
||||
if ($condition['field'] instanceof Condition) {
|
||||
$conditions =& $condition['field']->conditions();
|
||||
foreach ($conditions as $key => &$subcondition) {
|
||||
if (is_numeric($key)) {
|
||||
// As conditions can have subconditions, for example db_or(), the
|
||||
// function has to be called recursively.
|
||||
$this->condition_replace_string($search, $replace, $subcondition);
|
||||
$this->conditionReplaceString($search, $replace, $subcondition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,6 @@ class DefaultViewsTest extends ViewTestBase {
|
|||
|
||||
$node = $this->drupalCreateNode($values);
|
||||
|
||||
search_index($node->id(), 'node', $node->body->value, Language::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
$comment = array(
|
||||
'uid' => $user->id(),
|
||||
'status' => CommentInterface::PUBLISHED,
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Tests\SearchIntegrationTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Tests;
|
||||
|
||||
/**
|
||||
* Tests search integration filters.
|
||||
*/
|
||||
class SearchIntegrationTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'search');
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_search');
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Search integration tests',
|
||||
'description' => 'Tests search integration filters of views.',
|
||||
'group' => 'Views',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests search integration.
|
||||
*/
|
||||
public function testSearchIntegration() {
|
||||
// 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.
|
||||
$node['title'] = 'pizza';
|
||||
$node['body'] = array(array('value' => 'pizza'));
|
||||
$node['type'] = $type->type;
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
$this->drupalGet('node/1');
|
||||
$node_url = $this->getUrl();
|
||||
|
||||
$node['title'] = 'sandwich';
|
||||
$node['body'] = array(array('value' => 'sandwich with a <a href="' . $node_url . '">link to first node</a>'));
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
// Run cron so that the search index tables are updated.
|
||||
$this->cronRun();
|
||||
|
||||
// Test the various views filters by visiting their pages.
|
||||
// These are in the test view 'test_search', and they just display the
|
||||
// titles of the nodes in the result, as links.
|
||||
|
||||
// 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');
|
||||
|
||||
// Page with a keyword argument.
|
||||
$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->drupalGet('test-arg/sandwich');
|
||||
$this->assertNoLink('pizza', 'Pizza page is not on argument page');
|
||||
$this->assertLink('sandwich', 0, 'Sandwich page is on argument page');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
base_field: nid
|
||||
base_table: node
|
||||
core: 8.x
|
||||
description: 'Test view for Search integration'
|
||||
status: true
|
||||
display:
|
||||
page_2:
|
||||
display_plugin: page
|
||||
id: page_2
|
||||
display_title: 'Arg Page'
|
||||
position: 1
|
||||
display_options:
|
||||
display_description: ''
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
provider: node
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: '1'
|
||||
defaults:
|
||||
filters: false
|
||||
filter_groups: false
|
||||
arguments: false
|
||||
title: false
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
path: test-arg/%
|
||||
arguments:
|
||||
keys:
|
||||
id: keys
|
||||
table: node_search_index
|
||||
field: keys
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: '1'
|
||||
items_per_page: '25'
|
||||
separator: ''
|
||||
override: 0
|
||||
inline: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: unformatted_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
plugin_id: search
|
||||
provider: search
|
||||
title: 'Arg Page'
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 1
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: none
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
slave: false
|
||||
query_comment: false
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
items_per_page: '0'
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
row_class_special: true
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
provider: node
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
link_to_node: 1
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Title
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
provider: node
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: '1'
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
title: ''
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: 'Filter Page'
|
||||
position: 1
|
||||
display_options:
|
||||
display_description: ''
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
provider: node
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: '1'
|
||||
keys:
|
||||
id: keys
|
||||
table: node_search_index
|
||||
field: keys
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: optional
|
||||
value: pizza
|
||||
group: '1'
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: 0
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: search_keywords
|
||||
provider: search
|
||||
defaults:
|
||||
filters: false
|
||||
filter_groups: false
|
||||
title: false
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
path: test-filter
|
||||
title: 'Filter Page'
|
||||
label: 'Search Test'
|
||||
module: views
|
||||
id: test_search
|
||||
tag: ''
|
||||
uuid: f19c4fd2-af74-4d70-8500-a1037ca434bb
|
||||
langcode: en
|
Loading…
Reference in New Issue