Problem/Motivation

After Search Api 1.25 upgrade (from 1.24), numeric and date filter values previously set via the Views UI get truncated to the first character of the number/date.
Furthermore, if the newly introduced between/not-between operators are used, they have no effect on the query, even if they appear in the View's UI.
These problem persist in -dev after #3003742: Searching with dates throw error after #1783746 has been committed.

Search API 1.25 introduces the new class SearchApiViewsHandlerFilterNumeric which (in method otion_definition()) ultimately overrides the format of the filter's 'value' option: such option was previously expected to be a string (in views_handler_filter class), but is defined as array in the new class:

...
$options['value'] = array(
  'contains' => array(
    'value' => array('default' => ''),
    'min' => array('default' => ''),
    'max' => array('default' => ''),
  ),
);
...

The issue is further complicated by the fact that - as noted in #3003742: Searching with dates throw error after #1783746 - the value can be also passed as a nested array: I verified that this happens when the value is extracted from a date picker in an exposed filter.

I'll go in more detail in the comments. I mark this issue as major, as it can result in malfunction of views created before 1.25 and in the filter being ignored if the between/not-between operators are used.

Proposed resolution

I think that we need to make sure that the filter's $this->value property is always in the form of the array defined in the options. This needs to be done when initializing the filter and then again when an exposed filter is applied.
In the meantime, all non-exposed date and numeric filters saved before 1.25 need to be recreated via Views' UI. For between/not-between operators, it may be possible to save them as exposed filters with default values and hide the exposed form if needed.

Comments

pamatt created an issue. See original summary.

pamatt’s picture

Issue summary: View changes
pamatt’s picture

In this discussion, when I use the words "value" or "value of the filter" I mean the actual value to which entity fields are compared when a filter is defined in a view. When I refer to $this->value I mean the public property $value of a views filter handler declared in .../search_api/contrib/search_api_views/includes/handler_filter.inc. I checked all cases with a non-exposed date/numeric filter.
 
I count 6 cases:

  1. Views created before 1.25: Filter by comparison to a number
    In the view's UI a warning is issued:

    Warning: Illegal string offset 'value' in SearchApiViewsHandlerFilterNumeric->admin_summary() (line 189 of .../search_api/contrib/search_api_views/includes/handler_filter_numeric.inc).

    At line 175 of the same file $this->value is parsed

    $value = isset($this->value[0]) ? $this->value[0] : $this->value;
    

    As $this->value is a string in this case, $this->value[0] returns the first character of the string. $value['value'] is not set at line 189 - hence the warning - and is interpreted, again, as $value[0]. In the UI, the value of the filter is truncated.
    Nevertheless, the filter is handled correctly by SearchApiViewsHandlerFilter->query() at line 111 of .../search_api/contrib/search_api_views/includes/handler_filter.inc and the filter is succesfully applied to the view.
     

  2. Views created before 1.25: Filter by comparison to a date
    The UI is handled the same way as the previous case, throws the same warning and shows the filter's value truncated to the first character.
    The filter is added to the query by SearchApiViewsHandlerFilterDate->query() with the code committed after issue #3003742: Searching with dates throw error after #1783746 has been fixed (lines 154 et seq. in .../search_api/contrib/search_api_views/includes/handler_filter_date.inc):
    // Apparently, the value can come in here in various way.
    $value = $this->value;
    if (isset($value[0]['value'])) {
      $value = $value[0]['value'];
    }
    elseif (isset($value[0])) {
      $value = $value[0];
    }
     elseif (isset($value['value'])) {
       $value = $value['value'];
    }
    

    but this doesn't correctly take into account the fact that $this->value can come here as a string, so $value = $value[0] truncates the value to its first character. Most of the times this leads to a malfunctioning view: e.g. a filter for date=2018-10-24 gets passed to the query as date=2.
    As mentioned in #3003742: Searching with dates throw error after #1783746, there are cases in which $this->value[0] is actually a value of an array (e.g. if the filter is exposed), and the code works fine for that.
     

  3. Views created after 1.25: Filter by comparison to a number using any combination of >, <, = operators
    The code works. $this->value is
    array(
      'value' => '5000',
      'min' => '',
      'max' => '',
    );
    

    In this case SearchApiViewsHandlerFilterNumeric->admin_summary() finds the correct value at line 189 of .../search_api/contrib/search_api_views/includes/handler_filter_numeric.inc. The filter is properly added to the query by SearchApiViewsHandlerFilter->query() at line 111 of .../search_api/contrib/search_api_views/includes/handler_filter.inc at lines 110 seq., but it must be said that this happens sort of by fortune, because i think that the loop:

    while (is_array($this->value)) {
      $this->value = $this->value ? reset($this->value) : NULL;
    }
    

    cannot be trusted enough to extract the correct value of the filter.
     

  4. Views created after 1.25: Filter by comparison to an interval of numbers using between/not-between operators
    If the filter is not exposed, $this->value is:
    array(
      'value' => '',
      'min' => '4000',
      'max' => '5000',
    );
    

    but SearchApiViewsHandlerFilterNumeric->query() looks for $this->value[0]['min'], $this->value[0]['max']:

    ...
    if (in_array($this->operator, array('between', 'not between'), TRUE)) {
          $min = isset($this->value[0]['min']) ? $this->value[0]['min'] : '';
          $max = isset($this->value[0]['max']) ? $this->value[0]['max'] : '';
    ...
    

    and since they are not set in this case, the filter is simply ignored by the subsequent code and the view's results are unaffected by the filter.
     

  5. Views created after 1.25: Filter by comparison to a date using any combination of >, <, = operators
    No problem here. $this->value is
    array(
      'value' => '2018-10-24',
      'min' => '',
      'max' => '',
    );
    

    and is what both SearchApiViewsHandlerFilterNumeric->admin_summary() and SearchApiViewsHandlerFilterDate->query() are designed to handle.
     

  6. Views created after 1.25: Filter by comparison to an interval of dates using between/not-between operators
    The behavior is the same as in case number 4.; SearchApiViewsHandlerFilterDate->query() is at work here and the code is slightly different, but it all boils down to the fact that a non-exposed filter is ignored in the query.
     
pamatt’s picture

Title: Numeric and date filters not working properly after upgrade to 1.25 » Non-exposed numeric and date filters not working properly after upgrade to 1.25
pamatt’s picture

Status: Active » Needs work
pamatt’s picture

Issue summary: View changes
pamatt’s picture

Status: Needs work » Needs review
StatusFileSize
new4.62 KB

In this patch I propose to add a new protected method to SearchApiViewsHandlerFilterNumeric to make sure that the $value property is a correctly populated array. The method is called by overriding the init() method of the class and again in the query() method of both this class and of SearchApiViewsHandlerFilterDate.

drunken monkey’s picture

Thanks a lot for reporting this, and for your incredibly detailed analysis!
You’re right, we really neglected to take old views into account when making that change. Also, I wasn’t aware isset($value[0]) would be TRUE for non-empty strings, too – you never stop to learn, I guess.

Your proposed solution also looks pretty good. The patch just had a few trailing spaces, plus some coding standards problems. And one or two parts could be expressed more simply, I think – please see/test/review my attached revision!

In any case, again: thanks a lot!

pamatt’s picture

Well, thank you for all the hard work you put in the community! I completely agree with your revised patch #8. I also succesfully tested it against the 6 cases in comment #3.

Thank you again

  • drunken monkey committed 3aab52a on 7.x-1.x authored by pamatt
    Issue #3008849 by pamatt, drunken monkey: Fixed non-exposed numeric and...
drunken monkey’s picture

Status: Needs review » Fixed

Awesome, thanks for reporting back!
Committed.
Thanks again!

Status: Fixed » Closed (fixed)

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

amir simantov’s picture

Just a note: in my case the filters ARE exposed and the bug occurs, as well. Patch fixes the problem. Thanks for fixing and for committing!

akozoriz’s picture

There is a problem with exporting Views created before 1.25.
Filters values don't export correctly, actually filter values doesn't export at all.
I've added the path with custom export method to normalize filters export.