You are here

function filter_harmonizer_harmonize_and_record_filter_pairs in Views Filter Harmonizer 1.0.x

Same name and namespace in other branches
  1. 8 filter_harmonizer.module \filter_harmonizer_harmonize_and_record_filter_pairs()

When a View on a page is first loaded and if a context filter is present, we obey any associated /arg1/arg2/.. on the browser URL/address bar. Then, if regular exposed filters are present too for fields by the same names, and their form values are submitted, we obey those submitted values, discarding the contextual filter values used on initial page load.

For clarity and visual feedback to the user, we support the option to reflect, on the regular exposed filter form, the equivalent of the contextual argument value as appearing in the URL. Conversely, after exposed regular form values were selected and submitted, there's the option to reflect this in the browser address bar URL, as contextual arguments. Using contextual URL arguments is more concise then the verbose URL query string format, i.e. "?...".

The page with its filter settings can thus be concisely shared by copying the browser address bar and sending it in emails and on social media.

Parameters

ViewExecutable $view: The View. Its contextual or regular filters may be set in this call.

Return value

array An array with info about regular+contextual filter pairs on the View.

2 calls to filter_harmonizer_harmonize_and_record_filter_pairs()
filter_harmonizer_views_pre_build in ./filter_harmonizer.module
Implements hook_views_pre_build().
SettingsForm::buildForm in src/Form/SettingsForm.php
Form constructor.

File

./filter_harmonizer.module, line 63
filter_harmonizer.module

Code

function filter_harmonizer_harmonize_and_record_filter_pairs(ViewExecutable $view) {
  $view_id = $view
    ->id();
  $display = $view
    ->getDisplay();

  // e.g. 'block' or 'page' object
  $regular_filter_inputs = $display
    ->getPlugin('exposed_form') ? $view
    ->getExposedInput() : [];
  $display_id = $display->display['id'];

  // e.g. 'block_5' or 'page_1'
  $request = Drupal::request();
  $filter_pairs = [];

  //$pager = $display->getPlugin('pager');

  //$is_paged = !($pager instanceof Drupal\views\Plugin\views\pager\None);

  // Examine the current display being executed on the View and see if it has
  // both a non-empty contextual and a non-empty (exposed) regular filter,
  // operating on the same field. If it does "harmonize".
  // Also return essential filter data for later use eg. in
  // hook_page_attachments(), which is required to add JavaScript to the page,
  // while not having direct access to the View filters on the page.
  $regular_filters = $display
    ->getHandlers('filter');
  $contextual_filters = $display
    ->getHandlers('argument');
  $active_regular_filter_count = 0;
  $i = -1;
  foreach ($contextual_filters as $field_name => $contextual_filter) {

    // Temporary store filter values for easy access during this request.
    $filter_pair =& $filter_pairs[$view_id][$display_id][$field_name];

    // Record $contextual_filter->argument (from URL) as we need it now.
    // Normally this is done later in ViewExecutable::build($display_id).
    // We need to record all contextual filters, even those that do not have
    // a companion regular filter, in order to correctly apply URL argument
    // substitution, using '/all' for skipped filters.
    $i++;
    if ($is_contextual_filter_present = isset($view->args[$i])) {
      $contextual_filter->position = $i;
      $contextual_filter
        ->setArgument($view->args[$i]);
      $filter_pair['contextual']['argument'] = $contextual_filter->argument;
    }
    $filter_pair['contextual']['exception'] = $contextual_filter->options['exception']['value'];

    // eg. 'all';
    // Collect the companion regular filter value by the same name, if present.
    if (isset($regular_filters[$field_name])) {
      $regular_filter = $regular_filters[$field_name];
      $filter_pair['field_label'] = $regular_filter->definition['title'];
      $field_alias = $regular_filter->options['exposed'] ? $regular_filter->options['expose']['identifier'] : $field_name;
      $filter_pair['regular']['alias'] = $field_alias;
      $is_regular_filter_active = isset($regular_filter_inputs[$field_alias]);
      if ($is_regular_filter_active) {
        $active_regular_filter_count++;
        $filter_pair['regular']['value'] = $regular_filter->value = $regular_filter_inputs[$field_alias];
        $filter_pair['regular']['stringified'] = filter_harmonizer_stringify_regular_filter($regular_filter, $contextual_filter);
      }
      if ($is_contextual_filter_present) {
        if ($is_regular_filter_active) {

          // User has submitted regular filter values. So we have two competing
          // filters. Let's harmonize! Deactivate contextual now, before the
          // WHERE clause is generated that stuffs things up.
          unset($view->args[$i]);

          // Title now no longer reflects contextual filter value.
          // Better to have a blank title than a wrong title...
          $contextual_filter->options['title'] = '';
        }
        elseif (Drupal::config('filter_harmonizer.settings')
          ->get('filter_harmonizer_contextual_args_in_exposed_form')) {

          // No regular filter value set, get it from contextual arg.
          $regular_filter_inputs[$field_alias] = filter_harmonizer_formalize_contextual_arg($regular_filter, $contextual_filter);
        }
      }
    }
  }
  if (!$active_regular_filter_count && ($regular_filter_inputs = array_filter($regular_filter_inputs))) {
    $view
      ->setExposedInput($regular_filter_inputs);
  }
  return $filter_pairs;
}