Views reference is adding many query string variables to the pager URLs

Created on 5 June 2023, over 1 year ago
Updated 11 July 2024, 4 months ago

Problem/Motivation

Views reference configuration is being added as exposed input. The Drupal Core pagers take that exposed input and use it to build the query string for the pager. The result is an unnecessarily long URL containing the admin configuration of the views reference which is not needed for the actual render of the view, filters, or pagination.

This can result in "414 URI Too Long" error.

The developer of a ViewsReference plugin cannot stop too much configuration from being passed.

Steps to reproduce

Enable views reference field
Enable views ajax & views ajax history
Navigate twice through the pages (first ajax call does not have this problem, only 2nd or further does)

Proposed resolution

Allow ViewsReference plugin developers to use an optional ::massageFormOptions() method so they can reduce the
number of options that are saved.

Remaining tasks

Apply MR
Document how to use

User interface changes

None

API changes

None

Data model changes

None

πŸ› Bug report
Status

Closed: won't fix

Version

2.0

Component

Code

Created by

πŸ‡¬πŸ‡§United Kingdom scott_euser

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

Merge Requests

Comments & Activities

  • Issue created by @scott_euser
  • Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Waiting for branch to pass
  • Issue was unassigned.
  • Status changed to Needs review over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom scott_euser
  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    Views completely uses their own ViewAjaxController to remove elements from the query string.

    From views\src\Controller\ViewAjaxController.php:

          // Remove all of this stuff from the query of the request so it doesn't
          // end up in pagers and tablesort URLs.
          // @todo Remove this parsing once these are removed from the request in
          //   https://www.drupal.org/node/2504709.
          foreach ([
              'view_name',
              'view_display_id',
              'view_args',
              'view_path',
              'view_dom_id',
              'pager_element',
              'view_base_path',
              AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER,
              FormBuilderInterface::AJAX_FORM_REQUEST,
              MainContentViewSubscriber::WRAPPER_FORMAT,
            ] as $key) {
            $request->query->remove($key);
            $request->request->remove($key);
          }
    

    I think we need our own version to also remove the viewsreference key from the URL.

  • Status changed to Closed: works as designed about 1 year ago
  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    This is an issue for the views_ajax_history module. See πŸ“Œ AJAX GET in core: Alter ajax url query parameters Needs review for a way to fix this.

  • πŸ‡»πŸ‡³Vietnam chuyenlv

    I had a similar issue with the views enabled views_ajax_history module.

    The path for the views_ajax_history module to exclude query parameters from the pager is not good, because we have to update all the views enabled views Ajax history.

    So I created a patch to remove viewsreference parameter from request.

  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    That unfortunately breaks the ajax filtering and pagers. All the settings for the viewsreference field get lost on ajax requests if we do that. I found out the hard way (in production 😱).

  • πŸ‡»πŸ‡³Vietnam chuyenlv

    Hi @seanB
    My patch is remove viewsreference parameter from request before added it to $view->element['#viewsreference']
    The viewsreference_views_pre_view function will look like:

    /**
     * Implements hook_views_pre_view().
     */
    function viewsreference_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
      if (!isset($view->element['#viewsreference']) && empty($view->getRequest()->query->all('viewsreference'))) {
        return;
      }
    
      if (!empty($view->getRequest()->query->all('viewsreference'))) {
        $view->element['#viewsreference'] = $view->getRequest()->query->all('viewsreference');
        $view->getRequest()->query->remove('viewsreference');
        // For ajax views we reset all handlers and make the view initialize again
        // to allow changes from the settings plugins.
        $view->display_handler->handlers = [];
        $view->inited = FALSE;
      }
    
      // Let all settings plugins alter the view.
      $viewsreference_plugin_manager = \Drupal::service('plugin.manager.viewsreference.setting');
      $plugin_definitions = $viewsreference_plugin_manager->getDefinitions();
      if (isset($view->element['#viewsreference']['enabled_settings'])) {
        foreach ($view->element['#viewsreference']['enabled_settings'] as $enabled_setting) {
          if (!empty($plugin_definitions[$enabled_setting])) {
            $plugin_definition = $plugin_definitions[$enabled_setting];
            /** @var \Drupal\viewsreference\Plugin\ViewsReferenceSettingInterface $plugin_instance */
            $plugin_instance = $viewsreference_plugin_manager->createInstance($plugin_definition['id']);
            $value = $view->element['#viewsreference']['data'][$plugin_definition['id']] ?? $plugin_definition['default_value'];
            $plugin_instance->alterView($view, $value);
          }
        }
      }
    }

    I verified the viewsreference parameter still exists on the URL of views Ajax.

  • Status changed to Needs review about 1 year ago
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    1 pass
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update 9 months ago
    1 pass
  • Status changed to RTBC 9 months ago
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Okay I reviewed this and tested it out:

    1. Attempted to use dev branch of views_ajax_history, added viewsreference as an exclude parameter, unfortunately still hitting this error
    2. Attempted to use dev branch of viewsreference without patch, still hitting this error
    3. Attempted to use this patch (MR) and the issue is solved. Steps I followed to ensure I cover a mix:
      1. Go to page 2
      2. Go to page 3
      3. Filter by term
      4. Filter by term
      5. Go to page 2
      6. Go to page 3
      7. Filter by term

    Merged the patch into the merge request, deleted my original change, and hid patch. RTBC'ing I think okay since I did not make any changes, just patch > MR move.

  • πŸ‡¬πŸ‡§United Kingdom scott_euser
  • Status changed to Needs work 9 months ago
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Hmmm actually when I inspect the Network logs I can see its not actually fixing it. Going back to the drawing board on this a wee bit.

  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update 9 months ago
    1 pass
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update 9 months ago
    1 pass
  • Status changed to Needs review 9 months ago
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Okay with this approach, rather than trying to solve it in the module with a one-size-fits-all, we can simply allow the stored settings to be 'massaged' by the individual plugins as well.

    Basically the underlying problem is that if there are many options that can be selected from, each option is stored as a value even if it is not enabled. We know the defaults for the form have no values, so we know forms do not need them. This means we can safely remove any form state values that are not enabled.

    In most cases a plugin can just do:

      /**
       * Massage the form options.
       *
       * @param array $options
       *   The form options.
       *
       * @return array
       *   The updated options.
       */
      public function massageFormOptions($options) {
        return array_filter($options);
      }
    

    But we have some 10 or so plugins and some are more complex with many nested options depending on what is selected at top-level, which made me think one-size-fits-all will never work.

    Using this I was able to get strlen from 13598 down to 3687 for our typical use case, meaning the "414 URI Too Long" error no longer occurs. This suits our use case quite fine.

    I think this probably significantly safer for viewsreference module as well to handle as it does no harm and puts the owness on the individual ViewsReference plugin developers to sort it out.

    What I am unsure of is whether this should be applied to the interface; I have opted for no for now since that would be a breaking change

  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update 7 months ago
    1 pass
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Turns out massageFormValues() is not called when using a search_api View. Updated to handle that case as well. Again this is a much safer way as it does no possible harm to existing sites, it just enables developers to tackle the problem themselves.

  • Status changed to RTBC 7 months ago
  • πŸ‡ΊπŸ‡¦Ukraine nnevill Lutsk

    I've tried merge request https://git.drupalcode.org/project/viewsreference/-/merge_requests/31 on 2 different projects and it fix works as expected. So I think this is as good as RTBC.

  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update 6 months ago
    1 pass
  • Status changed to Closed: won't fix 5 months ago
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    It seems unlikely this will get in, so would suggest others avoid this and consider πŸ› Views reference is adding many query string variables to the pager URLs RTBC instead. I may consider adding a functionality similar to this in a separate module. Will update here if so.

  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    For anyone coming across this still having 414 issues, there is now https://www.drupal.org/project/viewsreference_extras β†’ which reloads the views reference configuration from the entity instead of compressing the configuration as is.

Production build 0.71.5 2024