Issue #2664530 by Lendude, slasher13, catch, alexpott, andrew.trebble: Views Combined fields filter with Contains
parent
50d30d975f
commit
71f2758196
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Filter handler which allows to search on multiple fields.
|
||||
|
@ -138,6 +139,40 @@ class Combine extends StringFilter {
|
|||
$this->query->addWhereExpression($this->options['group'], "$expression LIKE $placeholder", array($placeholder => '%' . db_like($this->value) . '%'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters by one or more words.
|
||||
*
|
||||
* By default opContainsWord uses add_where, that doesn't support complex
|
||||
* expressions.
|
||||
*
|
||||
* @param string $expression
|
||||
*/
|
||||
protected function opContainsWord($expression) {
|
||||
$placeholder = $this->placeholder();
|
||||
|
||||
// Don't filter on empty strings.
|
||||
if (empty($this->value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Match all words separated by spaces or sentences encapsulated by double
|
||||
// quotes.
|
||||
preg_match_all(static::WORDS_PATTERN, ' ' . $this->value, $matches, PREG_SET_ORDER);
|
||||
|
||||
// Switch between the 'word' and 'allwords' operator.
|
||||
$type = $this->operator == 'word' ? 'OR' : 'AND';
|
||||
$group = $this->query->setWhereGroup($type);
|
||||
$operator = Database::getConnection()->mapConditionOperator('LIKE');
|
||||
$operator = isset($operator['operator']) ? $operator['operator'] : 'LIKE';
|
||||
|
||||
foreach ($matches as $match_key => $match) {
|
||||
$temp_placeholder = $placeholder . '_' . $match_key;
|
||||
// Clean up the user input and remove the sentence delimiters.
|
||||
$word = trim($match[2], ',?!();:-"');
|
||||
$this->query->addWhereExpression($group, "$expression $operator $temp_placeholder", array($temp_placeholder => '%' . Database::getConnection()->escapeLike($word) . '%'));
|
||||
}
|
||||
}
|
||||
|
||||
protected function opStartsWith($expression) {
|
||||
$placeholder = $this->placeholder();
|
||||
$this->query->addWhereExpression($this->options['group'], "$expression LIKE $placeholder", array($placeholder => db_like($this->value) . '%'));
|
||||
|
|
|
@ -14,6 +14,11 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
*/
|
||||
class StringFilter extends FilterPluginBase {
|
||||
|
||||
/**
|
||||
* All words separated by spaces or sentences encapsulated by double quotes.
|
||||
*/
|
||||
const WORDS_PATTERN = '/ (-?)("[^"]+"|[^" ]+)/i';
|
||||
|
||||
// exposed filter options
|
||||
protected $alwaysMultiple = TRUE;
|
||||
|
||||
|
@ -267,7 +272,7 @@ class StringFilter extends FilterPluginBase {
|
|||
return;
|
||||
}
|
||||
|
||||
preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
|
||||
preg_match_all(static::WORDS_PATTERN, ' ' . $this->value, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $match) {
|
||||
$phrase = FALSE;
|
||||
// Strip off phrase quotes
|
||||
|
|
|
@ -95,6 +95,101 @@ class FilterCombineTest extends ViewsKernelTestBase {
|
|||
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Combine field filter with the 'word' operator.
|
||||
*/
|
||||
public function testFilterCombineWord() {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
$fields = $view->displayHandlers->get('default')->getOption('fields');
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', $fields + array(
|
||||
'job' => array(
|
||||
'id' => 'job',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'job',
|
||||
'relationship' => 'none',
|
||||
),
|
||||
));
|
||||
|
||||
// Change the filtering.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', array(
|
||||
'age' => array(
|
||||
'id' => 'combine',
|
||||
'table' => 'views',
|
||||
'field' => 'combine',
|
||||
'relationship' => 'none',
|
||||
'operator' => 'word',
|
||||
'fields' => array(
|
||||
'name',
|
||||
'job',
|
||||
),
|
||||
'value' => 'singer ringo',
|
||||
),
|
||||
));
|
||||
|
||||
$this->executeView($view);
|
||||
$resultset = array(
|
||||
array(
|
||||
'name' => 'John',
|
||||
'job' => 'Singer',
|
||||
),
|
||||
array(
|
||||
'name' => 'George',
|
||||
'job' => 'Singer',
|
||||
),
|
||||
array(
|
||||
'name' => 'Ringo',
|
||||
'job' => 'Drummer',
|
||||
),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Combine field filter with the 'allwords' operator.
|
||||
*/
|
||||
public function testFilterCombineAllWords() {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
$fields = $view->displayHandlers->get('default')->getOption('fields');
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', $fields + array(
|
||||
'job' => array(
|
||||
'id' => 'job',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'job',
|
||||
'relationship' => 'none',
|
||||
),
|
||||
));
|
||||
|
||||
// Set the filtering to allwords and simulate searching for a phrase.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', array(
|
||||
'age' => array(
|
||||
'id' => 'combine',
|
||||
'table' => 'views',
|
||||
'field' => 'combine',
|
||||
'relationship' => 'none',
|
||||
'operator' => 'allwords',
|
||||
'fields' => array(
|
||||
'name',
|
||||
'job',
|
||||
'age',
|
||||
),
|
||||
'value' => '25 "john singer"',
|
||||
),
|
||||
));
|
||||
|
||||
$this->executeView($view);
|
||||
$resultset = array(
|
||||
array(
|
||||
'name' => 'John',
|
||||
'job' => 'Singer',
|
||||
),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the filter can handle removed fields.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue