View source
<?php
namespace Drupal\views_complex_grouping\Plugin\views\style;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;
class ComplexGrouping extends StylePluginBase {
protected $usesRowPlugin = TRUE;
protected $usesGrouping = TRUE;
protected $usesOptions = TRUE;
protected $usesFields = TRUE;
protected $complexGroupingTheme = 'views_view_complex_grouping_level';
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$field_labels = $this->displayHandler
->getFieldLabels(TRUE);
foreach ($form['grouping'] as $index => $info) {
$form['grouping'][$index]['complex_grouping'] = [
'#type' => 'fieldset',
'#title' => t('Limit and extra fields for grouping field No. @num', [
'@num' => $index + 1,
]),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
];
$form['grouping'][$index]['complex_grouping']['grouping_fields'] = [
'#type' => 'select',
'#multiple' => TRUE,
'#title' => t('Selected'),
'#options' => $field_labels,
'#default_value' => $this
->getGroupingDefaultValues($index, 'grouping_fields'),
'#description' => t('Select which fields will be displayed alongside the field No. @num', [
'@num' => $index + 1,
]),
];
$form['grouping'][$index]['complex_grouping']['grouping_limit'] = [
'#type' => 'textfield',
'#title' => t('Items to display:'),
'#default_value' => $this
->getGroupingDefaultValues($index, 'grouping_limit'),
'#size' => 6,
'#element_validate' => [
[
get_called_class(),
'complexGroupingValidate',
],
],
'#description' => t('The number of rows to show under the field Nr. @num. Leave 0 to show all of them.', [
'@num' => $index + 1,
]),
];
$form['grouping'][$index]['complex_grouping']['grouping_offset'] = [
'#type' => 'textfield',
'#title' => t('Offset:'),
'#default_value' => $this
->getGroupingDefaultValues($index, 'grouping_offset'),
'#size' => 6,
'#element_validate' => [
[
get_called_class(),
'complexGroupingValidate',
],
],
'#description' => t('The row to start on.'),
];
}
}
private function getGroupingDefaultValues($index, $key) {
$default_option = NULL;
$options = $this->options['grouping'];
switch ($key) {
case 'grouping_limit':
$default_value = 0;
break;
case 'grouping_offset':
$default_value = 0;
break;
case 'grouping_fields':
default:
$default_value = NULL;
break;
}
$default_option = isset($options[$index]) ? $options[$index]['complex_grouping'][$key] ?: $default_value : $default_value;
return $default_option;
}
public function renderGrouping($records, $groupings = [], $group_rendered = NULL) {
if (is_string($groupings)) {
$rendered = $group_rendered === NULL ? TRUE : $group_rendered;
$groupings = [
[
'field' => $groupings,
'rendered' => $rendered,
],
];
}
$this
->renderFields($this->view->result);
$sets = [];
if ($groupings) {
foreach ($records as $index => $row) {
$set =& $sets;
foreach ($groupings as $level => $info) {
$field = $info['field'];
$rendered = isset($info['rendered']) ? $info['rendered'] : $group_rendered;
$rendered_strip = isset($info['rendered_strip']) ? $info['rendered_strip'] : FALSE;
$grouping = '';
$group_content = '';
if (isset($this->view->field[$field])) {
$group_content = $this
->getField($index, $field);
if ($this->view->field[$field]->options['label']) {
$group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
}
if ($rendered) {
$grouping = (string) $group_content;
if ($rendered_strip) {
$group_content = $grouping = strip_tags(htmlspecialchars_decode($group_content));
}
}
else {
$grouping = $this
->getFieldValue($index, $field);
if (!is_scalar($grouping)) {
$grouping = hash('sha256', serialize($grouping));
}
}
}
if (empty($set[$grouping])) {
$set[$grouping]['group'] = $group_content;
$set[$grouping]['level'] = $level;
$set[$grouping]['rows'] = [];
$set[$grouping]['fields'] = [];
foreach ($this->options['grouping'][$level]['complex_grouping']['grouping_fields'] as $field) {
$set[$grouping]['fields'][$field] = $this->rendered_fields[$index][$field];
}
}
$set =& $set[$grouping]['rows'];
}
$set[$index] = $row;
}
}
else {
if ($group_rendered === NULL) {
$old_style_sets = [];
foreach ($sets as $group) {
$old_style_sets[$group['group']] = $group['rows'];
}
$sets = $old_style_sets;
}
}
array_walk($sets, [
$this,
'complexGroupingRecursiveLimit',
]);
return $sets;
}
public function renderGroupingSets($sets) {
$output = [];
$branch = 0;
$theme_functions = $this->view
->buildThemeFunctions($this->complexGroupingTheme);
foreach ($sets as $set) {
$branch++;
$level = isset($set['level']) ? $set['level'] : 0;
$row = reset($set['rows']);
if (is_array($row) && isset($row['group'])) {
$single_output = [
'#theme' => $theme_functions,
'#view' => $this->view,
'#grouping' => $this->options['grouping'][$level],
'#grouping_branch' => $branch,
'#rows' => $set['rows'],
'#fields' => $set['fields'],
];
}
else {
if ($this
->usesRowPlugin()) {
foreach ($set['rows'] as $index => $row) {
$this->view->row_index = $index;
$set['rows'][$index] = $this->view->rowPlugin
->render($row);
}
}
$single_output = $this
->renderRowGroup($set['rows']);
$single_output['#grouping'] = $this->options['grouping'][$level];
$single_output['#grouping_branch'] = $branch;
$single_output['#fields'] = $set['fields'];
}
$single_output['#grouping_level'] = $level + 1;
$single_output['#title'] = $set['group'];
$output[] = $single_output;
}
unset($this->view->row_index);
return $output;
}
protected function complexGroupingRecursiveLimit(array &$group_data, $key = NULL, $level = 1) {
$settings = $this
->complexGroupingSettings($level - 1);
$settings['grouping_limit'] = $settings['grouping_limit'] != 0 ? $settings['grouping_limit'] : NULL;
$settings['grouping_offset'] = isset($settings['grouping_offset']) ? $settings['grouping_offset'] : 0;
$group_data['rows'] = array_slice($group_data['rows'], $settings['grouping_offset'], $settings['grouping_limit'], TRUE);
foreach ($group_data['rows'] as &$data) {
if (is_array($data) && isset($data['group']) && isset($data['rows'])) {
$this
->complexGroupingRecursiveLimit($data, NULL, $level + 1);
}
}
}
public static function complexGroupingValidate($element, FormStateInterface $form_state, $form) {
if (!is_numeric($element['#value'])) {
$form_state
->setError($element, t('%element must be numeric.', [
'%element' => $element['#title'],
]));
}
if ($element['#value'] < 0) {
$form_state
->setError($element, t('%element cannot be negative.', [
'%element' => $element['#title'],
]));
}
}
protected function complexGroupingSettings($index) {
if ($this->options['grouping'][$index] && $this->options['grouping'][$index]['complex_grouping']) {
return $this->options['grouping'][$index]['complex_grouping'];
}
else {
return [
'grouping_limit' => 0,
'grouping_offset' => 0,
];
}
}
}