Skip to content

Commit

Permalink
Fix #334: Add grid grouping functionalities
Browse files Browse the repository at this point in the history
  • Loading branch information
kartik-v committed Jul 7, 2015
1 parent 828a9d7 commit 9359dcc
Show file tree
Hide file tree
Showing 12 changed files with 768 additions and 43 deletions.
3 changes: 2 additions & 1 deletion CHANGE.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
Version 3.0.5
=============
**Date:** 02-Jul-2015
**Date:** 07-Jul-2015

1. (enh #322): Send serialized `data-key` when ExpandRowColumn has a composite key.
2. (enh #323): Prevent `pjax:complete` init script being called multiple times.
3. (enh #325): Various enhancements to client script registrations.
4. (enh #326): Zero width joiner for excel exports.
5. (enh #328): Add Turkish translations.
6. (enh #334): Add grid grouping functionalities.

Version 3.0.4
=============
Expand Down
12 changes: 6 additions & 6 deletions CheckboxColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ class CheckboxColumn extends \yii\grid\CheckboxColumn
* for the grid is set to FILTER_POS_BODY.
*/
public $mergeHeader = true;

/**
* @var string the script to initialize
* @var string the client script to initialize
*/
protected $_initScript = '';
protected $_clientScript = '';

/**
* @inheritdoc
Expand All @@ -119,8 +119,8 @@ public function init()
$view = $this->grid->getView();
$id = $this->grid->options['id'];
CheckboxColumnAsset::register($view);
$this->_initScript = "kvSelectRow('{$id}', '{$this->rowSelectedClass}');";
$view->registerJs($this->_initScript);
$this->_clientScript = "kvSelectRow('{$id}', '{$this->rowSelectedClass}');";
$view->registerJs($this->_clientScript);
}
$this->parseFormat();
$this->parseVisibility();
Expand All @@ -135,7 +135,7 @@ public function renderDataCell($model, $key, $index)
{
$options = $this->fetchContentOptions($model, $key, $index);
if ($this->rowHighlight) {
$this->initPjax($this->_initScript);
$this->initPjax($this->_clientScript);
Html::addCssClass($options, 'kv-row-select');
}
return Html::tag('td', $this->renderDataCellContent($model, $key, $index), $options);
Expand Down
87 changes: 87 additions & 0 deletions ColumnTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Json;
use \Closure;

/**
* Trait for all column widgets in yii2-grid
Expand All @@ -32,6 +34,7 @@ public function renderHeaderCell()
$this->headerOptions['rowspan'] = 2;
Html::addCssClass($this->headerOptions, 'kv-merged-header');
}
$this->headerOptions['data-col-seq'] = array_search($this, $this->grid->columns);
return parent::renderHeaderCell();
}

Expand All @@ -48,6 +51,7 @@ public function renderFilterCell()
if (isset($this->filterType) && $this->filterType === GridView::FILTER_SELECT2 && empty($this->filterWidgetOptions['pluginOptions']['width'])) {
$this->filterWidgetOptions['pluginOptions']['width'] = 'resolve';
}
$this->headerOptions['data-col-seq'] = array_search($this, $this->grid->columns);
return parent::renderFilterCell();
}

Expand Down Expand Up @@ -270,6 +274,7 @@ protected function fetchContentOptions($model, $key, $index)
if (trim($this->width) != '') {
Html::addCssStyle($options, "width:{$this->width};");
}
$options['data-col-seq'] = array_search($this, $this->grid->columns);
return $options;
}

Expand Down Expand Up @@ -321,4 +326,86 @@ protected function initPjax($script = '')
$event = 'pjax:complete.' . hash('crc32', $script);
$view->registerJs("{$cont}.off('{$event}').on('{$event}', function(){{$script}});");
}

/**
* Parses a value if Closure and returns the right value
*/
protected function parseVal($var, $model, $key, $index)
{
return $var instanceof Closure ?
call_user_func($var, $model, $key, $index, $this) :
$var;
}

/**
* Initializes grid grouping
*
* @return void
*/
protected function initGrouping()
{
if (empty($this->group)) {
return;
}
$view = $this->grid->getView();
$this->_columnKey = $this->getColumnKey();
Html::addCssClass($this->headerOptions, 'kv-grid-group-header');
Html::addCssClass($this->filterOptions, 'kv-grid-group-filter');
$this->headerOptions['data-group-key'] = $this->filterOptions['data-group-key'] = $this->_columnKey;
GridGroupAsset::register($view);
$id = $this->grid->options['id'];
$this->_clientScript = "kvGridGroup('{$id}');";
$view->registerJs($this->_clientScript);
}

/**
* Parses grid grouping and sets data attributes
*
* @return void
*/
protected function parseGrouping(&$options, $model, $key, $index)
{
if (empty($this->group)) {
return;
}
Html::addCssClass($options, 'kv-grid-group');
$options['data-group-key'] = $this->_columnKey;
if (!empty($this->groupOddCssClass)) {
$options['data-odd-css'] = $this->parseVal($this->groupOddCssClass, $model, $key, $index);
}
if (!empty($this->groupEvenCssClass)) {
$options['data-even-css'] = $this->parseVal($this->groupEvenCssClass, $model, $key, $index);
}
if (isset($this->subGroupOf)) {
$options['data-sub-group-of'] = $this->parseVal($this->subGroupOf, $model, $key, $index);
}
if (isset($this->groupedRow)) {
$options['data-grouped-row'] = $this->parseVal($this->groupedRow, $model, $key, $index);
}
if (!empty($this->groupHeader)) {
$options['data-group-header'] = Json::encode($this->parseVal($this->groupHeader, $model, $key, $index));
}
if (!empty($this->groupFooter)) {
$options['data-group-footer'] = Json::encode($this->parseVal($this->groupFooter, $model, $key, $index));
}
}

/**
* Generate an unique column key
*
* @return mixed
*/
protected function getColumnKey()
{
if (!empty($this->attribute)) {
$key = $this->attribute;
} elseif (!empty($this->label)) {
$key = $this->label;
} elseif (!empty($this->header)) {
$key = $this->header;
} else {
$key = get_class($this);
}
return hash('crc32', $key);
}
}
171 changes: 168 additions & 3 deletions DataColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* DataColumn is the default column type for the [[GridView]] widget.
*
* @author Kartik Visweswaran <[email protected]>
* @since 1.0
* @since 1.0
*/
class DataColumn extends \yii\grid\DataColumn
{
Expand Down Expand Up @@ -64,7 +64,7 @@ class DataColumn extends \yii\grid\DataColumn
* @see http://www.w3schools.com/cssref/pr_dim_width.asp
*/
public $width;

/**
* @var string the filter input type for each filter input. You can use one of the
* `GridView::FILTER_` constants or pass any widget classname (extending the
Expand Down Expand Up @@ -125,6 +125,162 @@ class DataColumn extends \yii\grid\DataColumn
*/
public $hidePageSummary = false;

/**
* @var boolean, whether to group grid data by this column. Defaults to `false`.
* Note that your query must sort the data by this column for it to be effective.
*/
public $group = false;

/**
* @var boolean|Closure, whether to add a separate group row for grouping. This is applicable only
* when `group` property is `true`. Defaults to `false`. If set to `true`, the column will be hidden
* and its value will be displayed in a separate row above. The default behavior is to show the grouped
* content in a separate column (when this property is `false`). If setup as a Closure, the signature
* of the function should be: `function ($model, $key, $index, $column)`, where `$model`, `$key`,
* and `$index` refer to the model, key and index of the row currently being rendered, and `$column`
* is a reference to the [[DataColumn]] object.
*/
public $groupedRow = false;

/**
* @var string|Closure, the odd group css class. Defaults to 'kv-group-odd'. If setup as a Closure,
* the signature of the function should be: `function ($model, $key, $index, $column)`, where
* `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being
* rendered, and `$column` is a reference to the [[DataColumn]] object.
*/
public $groupOddCssClass = 'kv-group-odd';

/**
* @var string|Closure, the even group css class. Defaults to 'kv-group-even'. If setup as a Closure,
* the signature of the function should be: `function ($model, $key, $index, $column)`, where
* `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being
* rendered, and `$column` is a reference to the [[DataColumn]] object.
*/
public $groupEvenCssClass = 'kv-group-even';

/**
* @var integer|Closure the column index of which this group is a sub group of. This is validated
* only if `group` is set to `true`. If setup as a Closure, the signature of the function should be:
* `function ($model, $key, $index, $column)`, where `$model`, `$key`, and `$index` refer to the model,
* key and index of the row currently being rendered, and `$column` is a reference to the [[DataColumn]]
* object.
*/
public $subGroupOf;

/**
* @var array|Closure configuration of the group header which will be displayed as a separate
* row above the group. If this is empty, no group header will be rendered. If setup as a Closure,
* the signature of the function should be: `function ($model, $key, $index, $column)`, where `$model`,
* `$key`, and `$index` refer to the model, key and index of the row currently being rendered, and
* `$column` is a reference to the [[DataColumn]] object. The following array keys are recognized:
* - `mergeColumns`: array, of columns that will be merged as `from, to` pairs. For example if you
* need to merge column numbers 0 to 2 and column numbers 3 to 6, you can set this as:
* ```
* [
* [0, 2], [3, 6]
* ]
* ```
* - `content`: array, header content for each column. You must set this as `$key => $value`, where
* `$key` is the 0 based index for the column, and `$value` is the content to display for the
* column. The `$value` can take in special function names to summarize values for the column.
* If set to one of `GridView::F_COUNT`, `GridView::F_SUM`, `GridView::F_AVG`, `GridView::F_MAX`,
* `GridView::F_MIN`, the values will be auto summarized.
*
* - `contentFormats`: array, header content formats for each column. This is only applicable currently only for
* number type or a custom type using a javascript callback. You must set this as `$key => $value`, where
* `$key` is the 0 based index for the column, and `$value` is the format settings for the column. The
* `$value` is a format specification setup as an array containing one or more of the following options:
* - `format`: string, whether `number` or `callback`
* - `decimals`: number, number of decimals (for number format only)
* - `decPoint`: string, decimals point character (for number format only). Defaults to `.`.
* - `thousandSep`: string, thousands separator character (for number format only). Defaults to `,`.
* - `func`: JsExpression, the javascript callback function (for callback format only). This must be setup as
* a javascript function of the signature: `function (source) { return custom_convert(source, data); }`. The
* parameters for the callback function that will be passed are:
* - `source`: string, the summary column source as set in `content` section if available
* - `data`: array, the text values of each of the child columns in this group.
* ```
* [
* 7 => ['format'=>'callback', 'func'=>new yii\web\JsExpression('customCallback')]
* 8 => ['format'=>'number', 'decimals'=>2, 'decPoint'=>'.', 'thousandSep'=>',']
* ]
* ```
*
* - `contentOptions`: array, header HTML attributes for each column. You must set this as `$key => $value`,
* where `$key` is the 0 based index for the column, and `$value` is the HTML attributes to apply for
* the column. The `$value` must be an array of HTML attributes for the table column.
* ```
* [
* 0 => ['style'=>'font-weight:bold'],
* 8 => ['style'=>'text-align:right']
* ]
* ```
*
* - `options`: array, HTML attributes for the group header row.
*/
public $groupHeader = [];

/**
* @var array|Closure configuration of the group footer which will be displayed as a separate
* row. If this is empty, no group footer will be rendered. If setup as a Closure, the signature
* of the function should be: `function ($model, $key, $index, $column)`, where `$model`, `$key`,
* and `$index` refer to the model, key and index of the row currently being rendered, and `$column`
* is a reference to the [[DataColumn]] object.
* `$column` is a reference to the [[DataColumn]] object. The following array keys are recognized:
* - `mergeColumns`: array, of columns that will be merged as `from, to` pairs. For example if you
* need to merge column numbers 0 to 2 and column numbers 3 to 6, you can set this as:
* ```
* [
* [0, 2], [3, 6]
* ]
* ```
*
* - `content`: array, footer content for each column. You must set this as `$key => $value`, where
* `$key` is the 0 based index for the column, and `$value` is the content to display for the
* column. The `$value` can take in special function names to summarize values for the column.
* If set to one of `GridView::F_COUNT`, `GridView::F_SUM`, `GridView::F_AVG`, `GridView::F_MAX`,
* `GridView::F_MIN`, the values will be auto summarized. For example:
* ```
* [
* 0 => 'Total',
* 8 => GridView::F_SUM
* ]
* ```
*
* - `contentFormats`: array, footer content formats for each column. This is only applicable currently only for
* number type or a custom type using a javascript callback. You must set this as `$key => $value`, where
* `$key` is the 0 based index for the column, and `$value` is the format settings for the column. The
* `$value` is a format specification setup as an array containing one or more of the following options:
* - `format`: string, whether `number` or `callback`
* - `decimals`: number, number of decimals (for number format only)
* - `decPoint`: string, decimals point character (for number format only). Defaults to `.`.
* - `thousandSep`: string, thousands separator character (for number format only). Defaults to `,`.
* - `func`: JsExpression, the javascript callback function (for callback format only). This must be setup as
* a javascript function of the signature: `function (source) { return custom_convert(source, data); }`. The
* parameters for the callback function that will be passed are:
* - `source`: string, the summary column source as set in `content` section if available
* - `data`: array, the text values of each of the child columns in this group.
* ```
* [
* 7 => ['format'=>'callback', 'func'=>new yii\web\JsExpression('customCallback')]
* 8 => ['format'=>'number', 'decimals'=>2, 'decPoint'=>'.', 'thousandSep'=>',']
* ]
* ```
*
* - `contentOptions`: array, footer HTML attributes for each column. You must set this as `$key => $value`,
* where `$key` is the 0 based index for the column, and `$value` is the HTML attributes to apply for
* the column. The `$value` must be an array of HTML attributes for the table column.
* ```
* [
* 0 => ['style'=>'font-weight:bold'],
* 8 => ['style'=>'text-align:right']
* ]
* ```
*
* - `options`: array, HTML attributes for the group footer row.
*/
public $groupFooter = [];

/**
* @var array of row data for the column for the current page
*/
Expand All @@ -135,6 +291,12 @@ class DataColumn extends \yii\grid\DataColumn
*/
protected $_view;

/**
* @var string the client script to initialize
*/
protected $_clientScript = '';
protected $_columnKey = '';

/**
* @inheritdoc
*/
Expand All @@ -152,6 +314,7 @@ public function init()
$this->checkValidFilters();
parent::init();
$this->setPageRows();
$this->initGrouping();
}

/**
Expand All @@ -160,6 +323,8 @@ public function init()
public function renderDataCell($model, $key, $index)
{
$options = $this->fetchContentOptions($model, $key, $index);
$this->parseGrouping($options, $model, $key, $index);
$this->initPjax($this->_clientScript);
return Html::tag('td', $this->renderDataCellContent($model, $key, $index), $options);
}

Expand Down Expand Up @@ -202,4 +367,4 @@ protected function renderFilterCellContent()
$options = ArrayHelper::merge($this->filterWidgetOptions, $options);
return $widgetClass::widget($options);
}
}
}
Loading

1 comment on commit 9359dcc

@yoyobdg
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been using the grouping grid, but there are problems in the summary footer, how to display the percentage that was obtained from the summary column 3 / summary column 4
I need advice from you, thank you

Please sign in to comment.