Notice: Undefined index: value in Drupal\views\Plugin\views\filter\NumericFilter->acceptExposedInput()

Created on 8 November 2016, about 8 years ago
Updated 12 September 2024, 3 months ago

Problem/Motivation

Numeric views filter (\Drupal\views\Plugin\views\filter\NumericFilter) and all child filters (Date, SearchApiDate, etc) throw a php notice (PHP < 8) or fatal error (PHP >= 8) when using grouped exposed filters with a group identifier that doesn't match the filter identifier.

Notice: Undefined index: value in Drupal\views\Plugin\views\filter\NumericFilter->acceptExposedInput()

or

TypeError: Cannot access offset of type string on string in Drupal\views\Plugin\views\filter\Date->acceptExposedInput()

Steps to reproduce

(require updates)

  1. Install Drupal standard profile
  2. Edit the default Content view at /admin/structure/views/view/content
  3. Add an "Authored on" filter
  4. Select "Expose this filter to visitors, to allow them to change it"
  5. Select "Grouped filters"
  6. Change the "Filter identifier" value from "created" to "date"
  7. Set the Grouping 1 label to "Last week", operator to "Is greater than", value type to "An offset from ..." and value "-7 days"
  8. Press Apply and then Save
  9. Navigate to /admin/content
  10. Set the "Authored on" filter to "Last week" and press "Filter".
  1. Expected behaviour: Filter is applied, correct results are shown
  2. Incorrect behaviour: error or notice when pressing "Filter"

Proposed resolution

Update \Drupal\views\Plugin\views\filter\NumericFilter::acceptExposedInput to target the exposed group identifier as per patch in #48.

Remaining tasks

  1. Add an automated test;

Workaround

If the Filter identifier is left unchanged when configuring the numeric views filter, then this bug will not be triggered.

🐛 Bug report
Status

Fixed

Version

10.2

Component
Views 

Last updated 2 days ago

Created by

🇺🇸United States dpolant Rochester NY

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇳🇿New Zealand ericgsmith

    Adding a new patch as #116 does not address the feedback in #120, and the patch #121 reverts the wrong line.

    I is not clear if #128 is related to this patch as I was unable to reproduce this error - but given the comment includes with "didn't fix the issue I have" implies this issue existed before the patch and so I think it is unrelated. @DiDebru can you please confirm?

  • 🇳🇿New Zealand ericgsmith

    Looks like we can remove the expected errors from the baseline too.

    Queued tests for 129 on 9.5 as this patch will not apply to 9.5 - and will check 10.1 / 10.0 on this patch

  • 🇧🇾Belarus dewalt

    I've made some investigation and I like to propose other solution.

    Why it happens?

    The warning is triggered in NumericFilter::acceptExposedInput() and it called twice. With grouped filter first time there is just an integer (e.g. 1) in input that triggers the warning, the second time input gets expected input as array with keys ['value', 'type', 'min', 'max']. It looks strange as it is expected to have the same input on each call.

    First call in ViewExposedForm::submitForm() that triggers warning:

        // Form input keys that will not be included in $view->exposed_raw_data.
        $exclude = ['submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset'];
        $values = $form_state->getValues();
        foreach (['field', 'filter'] as $type) {
          /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
          $handlers = &$form_state->get('view')->$type;
          foreach ($handlers as $key => $info) {
            if ($handlers[$key]->acceptExposedInput($values)) {
              $handlers[$key]->submitExposed($form, $form_state);
            }
            else {
              // The input from the form did not validate, exclude it from the
              // stored raw data.
              $exclude[] = $key;
            }
          }
        }
    

    Second time in ViewExecutable:_build() without warning

        $handlers = &$this->$key;
        foreach ($handlers as $id => $data) {
    
          if (!empty($handlers[$id]) && is_object($handlers[$id])) {
            $multiple_exposed_input = [0 => NULL];
            if ($handlers[$id]->multipleExposedInput()) {
              $multiple_exposed_input = $handlers[$id]->groupMultipleExposedInput($this->exposed_data);
            }
            foreach ($multiple_exposed_input as $group_id) {
              // Give this handler access to the exposed filter input.
              if (!empty($this->exposed_data)) {
                if ($handlers[$id]->isAGroup()) {
                  $converted = $handlers[$id]->convertExposedInput($this->exposed_data, $group_id);
                  $handlers[$id]->storeGroupInput($this->exposed_data, $converted);
                  if (!$converted) {
                    continue;
                  }
                }
                $rc = $handlers[$id]->acceptExposedInput($this->exposed_data);
                $handlers[$id]->storeExposedInput($this->exposed_data, $rc);
                if (!$rc) {
                  continue;
                }
              }
              $handlers[$id]->setRelationship();
              $handlers[$id]->query($this->display_handler->useGroupBy());
            }
          }
        }
    

    So for me there are two questions:

    • Why NumericFilter::acceptExposedInput() is called twice?
    • Why NumericFilter::convertExposedInput() that converts group input to expected format is missed in first case?(By the way I've tried to add it to first case, but it breaks the view execution)

    One more strange thing found

    Also I pay attention to broken $exclude variable, it declared twice in ViewExposedForm::submitForm() and isn't useful in first case.

        // Form input keys that will not be included in $view->exposed_raw_data.
        $exclude = ['submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset'];
        foreach (['field', 'filter'] as $type) {
              // ... Some code miss ...
              $exclude[] = $key;
        }
    
        // Rewrites upper results here.
        $exclude = ['submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset'];
        foreach ($values as $key => $value) {
          // Used last assignment only.
          if (!empty($key) && !in_array($key, $exclude)) {
            // ... Some code miss ...
          }
        }
    

    Changes history

    I've go to look for this changes in history and found that all this things above were added in this issue #2651102 ( patch ). The patch adds checkbox processing to form values and inside NumericFilter::acceptExposedInput() and non-working first $exclude assignment. The code before the patch:

        foreach (array('field', 'filter') as $type) {
          /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
          $handlers = &$form_state->get('view')->$type;
          foreach ($handlers as $key => $info) {
            $handlers[$key]->submitExposed($form, $form_state);
          }
        }
    

    Looks like NumericFilter::acceptExposedInput() was used to process checkboxes before call NumericFilter::submitExposed(), but:

    • NumericFilter doesn't use ::submitExposed() method, it inherits empty functionality
    • No core views filter has the method
    • No Search API views filter has the method
    • If custom module implements ::submitExposed(), it could care about checkbox processing inside
    • $exclude improvements aren't working

    Proposal

    I propose to revert a part of issue #2651102 described above, that causes warning and looks like doesn't have effective changes. @catch, @mikeker, welcome to comment!

  • 🇺🇸United States smustgrave

    This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

    Can confirm this issue and that the patch addresses it.
    It will need test coverage though.

  • 🇦🇺Australia mstrelan

    FWIW there are tests in the patches up until #131. I haven't really looked at the new approach but perhaps if we had an updated patch with the test from #130 and the fix from #131 we can confirm if this fixes the same issue.

  • 🇧🇾Belarus dewalt

    Existing tests changed to handle the notice. One more notice found when group identifier doesn't match to simple exposed one and fixed.

  • 🇧🇾Belarus dewalt

    One more small improvement to prevent possible notices if identifier is empty (looks it could happen on wrong config only), but anyway there is no sense to make additional check if parent::acceptExposedInput() returns FALSE.

  • The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

  • 🇧🇾Belarus dewalt

    Fixed CSpell issues, but phpcs warning isn't happens locally and surprises me at all, the variable isn't unused.

    FILE: ...l10/core/modules/views/src/Plugin/views/filter/NumericFilter.php
    ----------------------------------------------------------------------
    FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
    ----------------------------------------------------------------------
    411 | WARNING | Unused variable $value.
    ----------------------------------------------------------------------

  • The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

  • 🇮🇳India Akram Khan Cuttack, Odisha

    Added Updated patch and fixed CCF #137

  • 🇮🇳India Akram Khan Cuttack, Odisha
  • 🇧🇾Belarus dewalt

    @Akram, as far as I understand renaming "_test*" methods to "test*" means that it runs by phpunit engine itself, I afraid with the changes these methods called twice now, by phpunit engine and from ::testDateFilter() directrly.

  • Status changed to Needs review over 1 year ago
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    29,387 pass
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Took a quick look at #drupalsouth code sprint. Looks like function testDateFilter() can be dropped then.

  • Status changed to Needs work over 1 year ago
  • 🇺🇸United States smustgrave

    Took a brief look and seems there are some out of scope changes that were probably introduced in #139

  • 🇧🇾Belarus dewalt

    I don't support an idea to beatify all the file (not the changed lines only), I think doc-comments should be added in a scope of other issue, but not in a bug. By the example from previous patches I've just add `$value = NULL;` to pass PHPCS, rebased to 11.x branch and no more changed from #137.

    P.S. by the way PHPStorm not highlights the variable as unused(

  • Status changed to Needs review over 1 year ago
  • last update over 1 year ago
    29,402 pass
  • Status changed to RTBC over 1 year ago
  • 🇺🇸United States smustgrave

    Confirmed the problem in the issue summary following the steps.
    Note doesn't matter the identifier name, tried a few different ones but always got the error.

    Applying the patch #146 solved the issue and see it has test coverage as well.

    Thanks!

  • last update over 1 year ago
    29,416 pass
  • last update over 1 year ago
    29,436 pass
  • last update over 1 year ago
    29,437 pass
  • last update over 1 year ago
    29,437 pass
  • last update over 1 year ago
    29,445 pass
  • last update over 1 year ago
    29,450 pass
  • last update over 1 year ago
    29,499 pass
  • last update over 1 year ago
    29,499 pass
  • last update over 1 year ago
    29,508 pass
  • 6:19
    2:33
    Running
  • last update over 1 year ago
    29,552 pass, 1 fail
  • last update over 1 year ago
    29,552 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    29,435 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    29,553 pass
  • last update over 1 year ago
    29,436 pass
  • last update over 1 year ago
    29,801 pass
  • last update over 1 year ago
    29,811 pass
  • 🇷🇴Romania vasike Ramnicu Valcea

    it seems that patch actually passes.

    back to RTBC

  • last update over 1 year ago
    29,811 pass
  • last update over 1 year ago
    29,814 pass
  • last update over 1 year ago
    29,815 pass
  • Open on Drupal.org →
    Environment: PHP 8.2 & MySQL 8
    last update over 1 year ago
    Waiting for branch to pass
  • last update over 1 year ago
    29,826 pass
  • last update over 1 year ago
    29,879 pass
  • last update over 1 year ago
    29,877 pass
  • Status changed to Needs work over 1 year ago
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    Sometime between #130 and #131 this patch changed dramatically.

    Can we elaborate why?

    We had subsystem maintainer signoff on the approach in ##13 (see #113 and #120)

    The changes to remove all the special keys like form build ID definitely feel wrong to me.

    Can we go back to #130 and can those with the new approach elaborate why it isn't suitable?

  • 🇺🇸United States neclimdul Houston, TX

    Where did the unit test go? It was exposing several ways this could be triggered that had nothing to do with what ever is being changed in the exposed form handler I suspect might not being addressed based on a skim of the current patch.

  • Status changed to Needs review about 1 year ago
  • 🇧🇾Belarus dewalt

    @larowlan, I've made research of the issue and tried to provide explanation in #131. If anyone have some exact questions - you are welcome.

    @neclimdul Do you propose just to add the Unit test from #130?

  • Status changed to Needs work about 1 year ago
  • 🇺🇸United States smustgrave

    Think the confusion is that in 129-130 the size was about 8KB

    Then your post went to around 2KB with an explanation

    But then in 139 it jumped up to 13KB

    Was anything lost in that jump back down to 5KB, if tests were lost could we add back?

    May help to hide all patches but the right one (making sure it matches the issue summary, didn't check). Also quickest solution is turn to an MR

  • Assigned to xurizaemon
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Taking a look at this - aim to restore the test improvements from #130. Will move this to an MR per smustgrave suggestion.

  • Pipeline finished with Failed
    9 months ago
    Total: 176s
    #125746
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Ignore !7141 please. !7145 should be the tests from #130 and the solution approach from #131.

    Noting @larowlan comments in #151 I planned today at DrupalSouth to also produce an MR with the original approach which had maintainer agreement, that's not done yet.

  • Pipeline finished with Failed
    9 months ago
    Total: 570s
    #125768
  • Pipeline finished with Failed
    9 months ago
    Total: 586s
    #126064
  • Pipeline finished with Failed
    9 months ago
    Total: 177s
    #126073
  • Pipeline finished with Failed
    9 months ago
    Total: 365s
    #126075
  • Pipeline finished with Failed
    9 months ago
    Total: 212s
    #126512
  • Pipeline finished with Success
    9 months ago
    Total: 493s
    #126525
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Removing old patches from display, MR here is approach + tests from #130 updated.

    Interdiff is not cooperating with me trying to get an interdiff from 130 to the MR, so I'll summarise as best I can from visual review:

    • Change from 130 to core/phpstan-baseline.neon moves to core/.phpstan-baseline.php
    • In FilterDateTest.php we pass form options as strings not integers now ($this->getSession()->getPage()->findField($filter_identifier)->selectOption('1'); not ...->selectOption(1);
    • declare(strict_types=1); in NumericFilterTest.php
  • Status changed to Needs review 9 months ago
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Missed status update, back to NR

  • Status changed to Needs work 9 months ago
  • 🇺🇸United States smustgrave

    Hiding patches for clarity.

    Left a comment on the MR that may need to be clarified. If I'm correct that it's the wrong key then surprised nothing broke.

  • Pipeline finished with Success
    9 months ago
    Total: 595s
    #130860
  • Issue was unassigned.
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝

    Workaround added to issue description - if step 6 from the issue description is omitted, the bug does not appear.

    Reproducible on 11.x, updated repro details in the issue description to use "Authored on" as that makes it easier to verify results on an empty site (create two test nodes, set "Authored on" date back for one node). View config I tested with here.

  • Status changed to Needs review 9 months ago
  • 🇳🇿New Zealand xurizaemon Ōtepoti, Aotearoa 🏝
  • Status changed to RTBC 9 months ago
  • 🇺🇸United States smustgrave

    Test coverage can be seen https://git.drupalcode.org/issue/drupal-2825860/-/jobs/1173292

    Following the issue summary believe I am able to see the issue and the MR does address it.

    Also appears all feedback for this bug has been addressed so believe this one is good.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    Assigning issue credit. Not crediting screenshot confirming bug, or works for me, or doesn't work for me. Trying to credit people who moved the fix and issue forward. If I make a mistake I'm sorry! Thanks.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    alexpott changed the visibility of the branch 2825860-notice-undefined-index to hidden.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    Committed and pushed ba08bc0dcb to 11.x and b5f62fa4ae to 10.3.x and f78530b4a7 to 10.2.x. Thanks!

    • alexpott committed f78530b4 on 10.2.x
      Issue #2825860 by xurizaemon, Matroskeen, dewalt, neclimdul, joseph....
  • Status changed to Fixed 9 months ago
    • alexpott committed b5f62fa4 on 10.3.x
      Issue #2825860 by xurizaemon, Matroskeen, dewalt, neclimdul, joseph....
    • alexpott committed 64de6a69 on 11.x
      Issue #2825860 by xurizaemon, Matroskeen, dewalt, neclimdul, joseph....
  • Automatically closed - issue fixed for 2 weeks with no activity.

  • 🇮🇳India smitghelani Surat, Gujarat

    Re-roll of patch #48 for branch 10.3.x.

  • 🇧🇷Brazil irafah

    I had the same issues, applied the patch from #175 and it worked correctly. It seems it is still needed even after the previous merge at #170

  • 🇬🇧United Kingdom rossb89 Bristol

    Agreed. The work here that was committed in 10.2.x, 10.3.x, 11.x is absolutely needed, but i'm still having issues with the actual value.

    Inside here:

    if (!empty($info[$this->operator]['values'])) {
      switch ($info[$this->operator]['values']) {
        case 1:
          if ($value['value'] === '') {
            return FALSE;
          }
          break;
    
        case 2:
          if ($value['min'] === '' && $value['max'] === '') {
            return FALSE;
          }
          break;
      }
    }
    

    for grouped (checkbox?) input, $value is this:

    array (
      1 => '1',
    )
    

    which causes the error still as there is no 'value' key to check against for this grouped exposed input value.

    Patch 175 which is a re-roll of 48 actually checks to inspect $value to make sure that the expected keys are there which seems to be what's needed in some circumstances?

    There is another issue here in relation to this though... where ViewsExposedForm::submitForm() https://git.drupalcode.org/project/drupal/-/blob/10.3.x/core/modules/vie...

    seems to declare an $exclude variable at the top of the function, which is added to if acceptExposedInput() returns false but then immediately beneath this outside of the loop, it's declared again (with the same initial keys) which overrides any entries that were added by this loop!

    So you can get into a weird situation where the handler for the exposed input returns false, but then beneath it can still be processed as it's no longer inside of $exclude... which in my circumstances is actually useful as I want the exposed filter value to be valid... but technically it shouldn't be doing this!?

    Maybe someone with some more knowledge around this could provide some insights about the data structure of grouped $value's and how this is expected to work without the additions in patch 175...

Production build 0.71.5 2024