I have some inspired users helping with creating this filter for the Name Field module and I was wondering if we should make this case insensitive over all databases rather than being dependent of the SQL server. The change in views_handler_filter::op_contains() is:
- $where->where("$fulltext_field LIKE $placeholder", array($placeholder => '%' . db_like($word) . '%'));
+ $where->condition($fulltext_field, '% ' . db_like($word) . '%', 'LIKE');
The first is the way that this is handled internally with strings in Views, but PostgreSQL will be using LIKE rather than ILIKE, while MySQL would work as expected. This change doesn't appear to cause issues, but I would love to know if this could causes issues. The full method is:
class name_handler_filter_name_fulltext extends views_handler_filter {
function query() {
$name_table = $this->ensure_my_table();
$field = "$this->table_alias.$this->real_field";
$fulltext_field = "CONCAT(' ', COALESCE({$field}_title, ''), ' ', COALESCE({$field}_given, ''), ' ', COALESCE({$field}_middle, ''), ' ', COALESCE({$field}_family, ''), ' ', COALESCE({$field}_generational, ''), ' ', COALESCE({$field}_credentials, ''))";
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}($fulltext_field);
}
}
function op_word($fulltext_field) {
$where = $this->operator == 'word' ? db_or() : db_and();
// Don't filter on empty strings.
if (empty($this->value)) {
return;
}
$words = preg_split('/ /', $this->value, -1, PREG_SPLIT_NO_EMPTY);
foreach($words as $word) {
$placeholder = $this->placeholder();
$where->condition($fulltext_field, '% ' . db_like($word) . '%', 'LIKE');
}
$this->query->add_where($this->options['group'], $where);
}
}
This also raises the question is the code in handlers/views_handler_filter_string.inc done in a consistent DB independent way?
function op_word($field) {
$where = $this->operator == 'word' ? db_or() : db_and();
preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$phrase = false;
// Strip off phrase quotes
if ($match[2]{0} == '"') {
$match[2] = substr($match[2], 1, -1);
$phrase = true;
}
$words = trim($match[2], ',?!();:-');
$words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
foreach ($words as $word) {
$placeholder = $this->placeholder();
$where->where("$field LIKE $placeholder", array($placeholder => '%' . db_like(trim($word, " ,!?")) . '%'));
}
}
Thanks
Comments
Comment #1
dawehnerThis sounds like a bit like a bug here :)
Comment #2
alan d. commentedThat resolves the argument in the other thread :) Thanks.
[Edit] For reference, see #1029534: PostgreSQL case sensitivity in filter.
Comment #3
dealancer commentedHere is a patch that fixes it in views_handler_filter_string!
Comment #4
dawehnerNot relying on custom sql code but using directly dbtng code is always cool.
This handler is actually tested quite well, so i committed this patch to 7.x-3.x as it looks fine.
Thanks for providing a patch. For other places, which might exist, reopen this issue or better create a new specific issue
Comment #5
alan d. commentedNice work guys!
Question from left field, how would you map the db LIKE operator in an expression inside of the view handler?
This was the actually issue that I was looking at when posting this thread. :)
Comment #6
dealancer commented@Alan D., we could use custom sql query with using LOWERCASE keyword which will work fine, please see http://drupal.org/node/1369618#comment-5569090.
What about the issue you are speaking it looks like it is a feature of Drupal DB API. Please see http://drupalcontrib.org/api/drupal/drupal%21includes%21database%21query...
Comment #7
alan d. commented"it looks like it is a feature of Drupal DB API": Yes it is, but how to bridge across to the views DB adapters / wrappers safely from within the views handler itself...