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

CommentFileSizeAuthor
#3 string_filter_case-1425184-3.patch702 bytesdealancer

Comments

dawehner’s picture

Category: support » bug

This sounds like a bit like a bug here :)

alan d.’s picture

That resolves the argument in the other thread :) Thanks.

[Edit] For reference, see #1029534: PostgreSQL case sensitivity in filter.

dealancer’s picture

Title: Custom views_handler_filter handler and case sensitivity » views_handler_filter_string and case sensitivity: any word or all words search
Status: Active » Needs review
StatusFileSize
new702 bytes

Here is a patch that fixes it in views_handler_filter_string!

dawehner’s picture

Status: Needs review » Fixed

Not 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

alan d.’s picture

Nice work guys!

Question from left field, how would you map the db LIKE operator in an expression inside of the view handler?

    $fulltext_field = "CONCAT(' ', COALESCE({$field}_title, ''), ' ', COALESCE({$field}_given, ''), ' ', COALESCE({$field}_middle, ''), ' ', COALESCE({$field}_family, ''), ' ', COALESCE({$field}_generational, ''), ' ', COALESCE({$field}_credentials, ''))";
  $operator = ($mapped = $this->query->mapConditionOperator('LIKE') ? $mapped : 'LIKE');

This was the actually issue that I was looking at when posting this thread. :)

dealancer’s picture

@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...

$condition_fragments[] = ' (' . $connection->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
alan d.’s picture

"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...

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.