You are here

views_merge_rows.module in Views Merge Rows 8

Same filename and directory in other branches
  1. 8.2 views_merge_rows.module
  2. 7 views_merge_rows.module

Registers View API information

File

views_merge_rows.module
View source
<?php

/**
 * @file
 * Registers View API information
 */
use Drupal\views\ViewExecutable;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;

/**
 * Implements hook_theme().
 */
function views_merge_rows_theme($existing, $type, $theme, $path) {
  $base = [
    'render element' => 'form',
    'path' => drupal_get_path('module', 'views_merge_rows') . '/templates',
  ];
  return [
    'merge_rows_theme' => $base + [
      'template' => 'merge-rows-theme',
    ],
  ];
}

/**
 * Implements hook_views_pre_render().
 *
 * Merges the rows according to the settings for current display.
 */
function views_merge_rows_views_pre_render(ViewExecutable $view) {
  $items_per_page = get_items_per_page_for_current_display($view);
  $extender = $view->display_handler
    ->getExtenders()['views_merge_rows'];
  if (isset($extender)) {
    $options = $extender
      ->get_options();
  }
  else {
    $options = NULL;
  }
  if (!is_null($options) && $options['merge_rows'] && $items_per_page > 0) {
    $view
      ->setItemsPerPage(0);
  }
  if (!is_null($options) && $options['merge_rows'] != FALSE) {
    $view->style_plugin
      ->renderFields($view->result);
    $rendered_fields = $view->style_plugin
      ->getRenderedFields();
    $filters = [];

    // Array, where each element corresponds to the row after removing the merged
    // rows. This element is an array of fields (field_name is used as a key).
    // The values of this field depends on the merge_option as follows:
    // merge_unique - array of unique values from all merged rows
    // merge - array of values from all merger rows
    // filter - the value from the first merged rows (all values from the merged
    // rows are the same)
    // first_value - the value from the first merged rows
    // count_unique - array of unique values from all merged rows
    // count - the number of merged rows.
    $merged_rows = [];
    foreach ((array) $rendered_fields as $row_index => $rendered_row) {
      $filter_value = '';
      foreach ($options['field_config'] as $field_name => $field_config) {
        if ($field_config['merge_option'] == 'filter') {
          $filter_value .= $rendered_row[$field_name];
        }
      }
      if (!array_key_exists($filter_value, $filters)) {
        $merged_row_replaced = FALSE;
        $filters[$filter_value] = $row_index;
        $merged_row = [];
        foreach ($options['field_config'] as $field_name => $field_config) {
          switch ($field_config['merge_option']) {
            case 'count_unique':
              if (!in_array($rendered_row[$field_name], $merged_row[$field_name])) {
                $merged_row[$field_name][] = $rendered_row[$field_name];
              }
              break;
            case 'merge_unique':
            case 'merge':
            case 'sum':
            case 'average':
            case 'std_deviation':
              $merged_row[$field_name] = [
                $rendered_row[$field_name],
              ];
              break;
            case 'count':
              $merged_row[$field_name] = 1;
              break;
            case 'filter':
            case 'first_value':
            case 'highest_value':
            case 'lowest_value':
              $merged_row[$field_name] = $rendered_row[$field_name];
              break;
          }
        }
        $merged_rows[$row_index] = $merged_row;
      }
      else {
        $merge_row_index = $filters[$filter_value];
        $merged_row = $merged_rows[$merge_row_index];
        foreach ($options['field_config'] as $field_name => $field_config) {
          switch ($field_config['merge_option']) {
            case 'merge_unique':
            case 'count_unique':
              if (!empty($rendered_row[$field_name]) && !in_array($rendered_row[$field_name], $merged_row[$field_name])) {
                $merged_row[$field_name][] = $rendered_row[$field_name];
              }
              break;
            case 'merge':
            case 'sum':
            case 'average':
            case 'std_deviation':
              $merged_row[$field_name][] = $rendered_row[$field_name];
              break;
            case 'count':
              $merged_row[$field_name] = $merged_row[$field_name] + 1;
              break;
            case 'filter':
            case 'first_value':

              // Do nothing - we already have a value from the first merged row.
              break;
            case 'highest_value':

              // Strip the HTML from the rendered and merged fields data and grab
              // the raw value.
              $rendered_row_data = floatval((string) $rendered_row[$field_name]);
              $merged_row_data = floatval((string) $merged_row[$field_name]);

              // Place the higher value into the merged row array.
              if ($rendered_row_data > $merged_row_data) {
                $merged_row[$field_name] = $rendered_row[$field_name];
                $merged_row_replaced = TRUE;
              }
              else {
                views_merge_rows_unset_row($view, $row_index);
                $merged_row_replaced = FALSE;
              }
              break;
            case 'lowest_value':

              // Strip the HTML from the rendered and merged fields data and grab
              // the raw value.
              $rendered_row_data = floatval((string) $rendered_row[$field_name]);
              $merged_row_data = floatval((string) $merged_row[$field_name]);
              if (!isset($first_value)) {
                $first_value = TRUE;
              }

              // Place the lower value into the merged row array.
              if ($first_value && !empty($rendered_row[$field_name])) {
                $merged_row[$field_name] = $rendered_row[$field_name];
                $merged_row_replaced = TRUE;
                $first_value = FALSE;
              }
              elseif ($rendered_row_data <= $merged_row_data && !empty($rendered_row[$field_name])) {
                $merged_row[$field_name] = $rendered_row[$field_name];
                $merged_row_replaced = TRUE;
              }
              else {
                views_merge_rows_unset_row($view, $row_index);
                $merged_row_replaced = FALSE;
              }
              break;
          }
        }
        switch ($field_config['merge_option']) {
          case 'highest_value':
          case 'lowest_value':

            // If we replaced the row with a higher value, then update all array
            // indexes with the new index values.
            if ($merged_row_replaced == TRUE) {
              $merged_rows[$row_index] = $merged_row;

              // Getting the items per page setting from the view display.
              $items_per_page = get_items_per_page_for_current_display($view);
              $total_items = $view->total_rows;

              // Getting pager values as per merged rows.
              $merged_rows_total_num = count($merged_rows);
              if ($items_per_page > 0 && $merged_rows_total_num > $items_per_page) {
                $current_page_num = isset($view->query->pager->current_page) ? $view->query->pager->current_page : 0;
                $page_rows = $all_pages = 0;
                foreach ($merged_rows as $row_index => $merged_row) {
                  if ($page_rows >= $items_per_page) {
                    $all_pages++;
                    $page_rows = 1;
                  }
                  else {
                    $page_rows++;
                  }

                  // Unsetting all results but the ones from current page.
                  if ($all_pages != $current_page_num) {
                    views_merge_rows_unset_row($view, $row_index);
                  }
                }

                // Attaching the pager with correct values.
                pager_default_initialize($merged_rows_total_num, $items_per_page);
              }
              $view->total_rows = $total_items;
              $filters[$filter_value] = $row_index;

              // Remove the previous highest or lowest value from the view.
              views_merge_rows_unset_row($view, $merge_row_index);
              break;
            }
            $first_value = TRUE;
            break;
          default:
            views_merge_rows_unset_row($view, $row_index);
            $merged_rows[$merge_row_index] = $merged_row;
            break;
        }
      }
    }

    // Store the merged rows back to the view's style plugin.
    foreach ($merged_rows as $row_index => $merged_row) {
      foreach ($options['field_config'] as $field_name => $field_config) {
        switch ($field_config['merge_option']) {
          case 'merge':
          case 'merge_unique':
            foreach ($merged_row[$field_name] as $field_index => $field_value) {
              if (empty($field_value)) {
                unset($merged_row[$field_name][$field_index]);
              }
            }
            if ($field_config['exclude_first']) {
              array_shift($merged_row[$field_name]);
            }
            $value_count = count($merged_row[$field_name]);
            $i = 1;
            foreach ($merged_row[$field_name] as $field_index => $field_value) {
              if ($i != $value_count) {
                $merged_row[$field_name][$field_index] = $field_config['prefix'] . $field_value . $field_config['separator'] . $field_config['suffix'];
              }
              else {
                $merged_row[$field_name][$field_index] = $field_config['prefix'] . $field_value . $field_config['suffix'];
              }
              $i++;
            }
            unset($i);
            unset($value_count);
            $view->style_plugin
              ->setRenderedField(implode($merged_row[$field_name]), $row_index, $field_name);
            break;
          case 'sum':
          case 'average':
          case 'std_deviation':
            $sum = 0;
            if ($field_config['merge_option'] == 'average' || $field_config['merge_option'] == 'std_deviation') {
              $sum_square = 0;
              $count_field_values = 0;
            }
            $count_field_values = 0;
            foreach ($merged_row[$field_name] as $field_index => $field_value) {
              if (!empty($field_value)) {
                $sum += floatval((string) $field_value);
                if ($field_config['merge_option'] == 'std_deviation') {
                  $sum_square += floatval((string) $field_value) * floatval((string) $field_value);
                }
                $count_field_values++;
              }
            }
            if ($field_config['merge_option'] == 'average' || $field_config['merge_option'] == 'std_deviation') {
              $average = $sum / $count_field_values;
            }
            if ($field_config['merge_option'] == 'average') {
              $sum = $average;
            }
            if ($field_config['merge_option'] == 'std_deviation') {
              $average_square = $sum_square / $count_field_values;
              if ($count_field_values = 1) {
                $sum = 0;
              }
              else {
                $sum = $count_field_values / ($count_field_values - 1) * ($average_square - $average * $average);
                $sum = sqrt($sum);
              }
            }
            $view->style_plugin
              ->setRenderedField($sum, $row_index, $field_name);
            break;
          case 'count_unique':
            $view->style_plugin
              ->setRenderedField(count($merged_row[$field_name]), $row_index, $field_name);
            break;
          case 'count':
          case 'filter':
          case 'first_value':
          case 'highest_value':
          case 'lowest_value':
            $view->style_plugin
              ->setRenderedField($merged_row[$field_name], $row_index, $field_name);
            break;
          case 'count_unique':
            if ($field_config['exclude_first']) {
              array_shift($merged_row[$field_name]);
            }
            $view->style_plugin
              ->setRenderedField(count($merged_row[$field_name]), $row_index, $field_name);
            break;
        }
      }
    }
  }
}

/**
 * Unsets the given row from the current display.
 *
 * @param object $view
 *   View object.
 *
 * @param int $row_index
 *   Supplied row index value.
 */
function views_merge_rows_unset_row(ViewExecutable $view, $row_index) {
  unset($view->result[$row_index]);
  --$view->total_rows;
}

/**
 * Returns item per page for the current display.
 *
 * @param object $view
 *   View object.
 *
 * @return int $items_per_page
 *   Returns number of items per page set for the current display of the view.
 */
function get_items_per_page_for_current_display(ViewExecutable $view) {
  $items_per_page = 0;
  $uri = \Drupal::request()
    ->getRequestUri();
  $uri_parts = parse_url($uri);
  if (!empty($uri_parts['scheme'])) {
    $currentURI = Url::fromUri(\Drupal::request()
      ->getRequestUri());
    if (isset($currentURI['query']['items_per_page'])) {
      $items_per_page = $currentURI['query']['items_per_page'];
    }
  }
  elseif (isset($view->pager->options['items_per_page'])) {
    $items_per_page = $view
      ->getItemsPerPage();
  }
  elseif (isset($view->pager->options['type']) && $view->pager->options['type'] == 'none') {
    $items_per_page = 0;
  }
  else {
    $items_per_page = $view
      ->getItemsPerPage();
  }
  return $items_per_page;
}

Functions

Namesort descending Description
get_items_per_page_for_current_display Returns item per page for the current display.
views_merge_rows_theme Implements hook_theme().
views_merge_rows_unset_row Unsets the given row from the current display.
views_merge_rows_views_pre_render Implements hook_views_pre_render().