yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.23k stars 6.91k forks source link

Add Events to GridView #6966

Closed Insolita closed 8 years ago

Insolita commented 9 years ago

GridView as component may have behaviors, but it`s mindlessly in practice - It would be nice if we can modify logic in methods such as init, guessColumns, renderFilters etc. by attach behaviors on events from this methods, instead of make different classes extended GridView or super-universal such as kartik\grid project

githubjeka commented 9 years ago

Example would be introduced of clarity into the issue.

samdark commented 9 years ago
  1. What are you trying to achieve?
  2. Why inheritance doesn't work for you?
  3. Which events would help for which cases?
Insolita commented 9 years ago

Inheritance work for me, but for example - exists gridview class for sortable columns, exist gridview for grouping columns, exist kartk plugin... with many useful, but sometimes redundant functionality In my projects i need in all types, and i if want add some more functionality... such as support for dynamic change page size, or columns visibility, or smthing other, i must extends all of this, and write similar code, move functional from one to another and have many dependecies from their developer changes...Or create own casino with blackjack... May be not all of customizations are in need of events, but i think behavior-way made it more flexible for usage - need in pdf-export - attach behavior, need in floatheader - attach it etc.

githubjeka commented 9 years ago

In words, I like it. But implementation

samdark commented 9 years ago

Sounds OK but are events sufficient for creating such behaviors?

Faryshta commented 9 years ago

I propose to create a new class extending GridView named ActiveGridView

The reasons:

When making reports for example you use need to do things like calculate the total sum of a column, the average in a date range, the total sum in a row, the percentaje of a column based on the total sum.

Example

Sales

Month Shoes Tshirts Pants Total
xx Quantity Percentage Quantity Percentage Quantity Percentage xx
January 10 20% 15 30% 25 50% 50
February 12 25% 24 50% 12 50% 48
-------- ---- ------- ------ ------- ----- -------- ----
Total 22 22% 39 38% 37 40% 98
Average per month 11 22% 19.5 38% 18.5 40% 49

Currently with GridView this would be a lot of work, so much it would be easier to generate the data using yii\db\Query and then simply use the yii views to do a lot of echo's on the data provided by the query.

I propose that ActiveGridView and ActiveColumn classes sp that you can call behaviors that communicate on each part of the process.

Example:

SumBehavior : everytime a cell is processed in a column it adds the value to a total and echo's it on the footer.

AverageBehavior : everytime a cell is processed it adds the value to a total and keeps a count on the number of cells have been processed, to echo's it on the footer.

SumRowBehavior : Everytime a cell in a row in processed it adds the value to a target column.

PercentageRowBehavior : configured with a 'totalColumn' and a parentColumn which will basically calculate the percentage of parentColumn with respect of totalColumn.

They will be used like this

$grid = ActiveGridView::begin([
    'dataProvider' => $dataProvider,
    'behaviors' => [
        'sum' => SumBehavior::className(),
        'average' => AverageBehavior::className(),
        'rowSum' => [
            'class' => SumRowBehavior::className(),
            'totalColumn' => 'total', //adds the value of the column attribute to this column
        ],
        'averageRow' => [
            'class' => AverageRowBehavior::className(),
            'totalColumn' => 'total', //gets the value of this column to calculate the average
        ],
    ],
    'columns' => [
        'month' => [
             'label' => 'Month',
             'attribute' => 'month',
             'format' => ['date', 'php:m']
        ],
        'shoes' => [
             'class' => ActiveColumn::className(),
             'label' => 'Shoes',
             'attribute' => 'shoes',
             'behaviors' => ['sum', 'average', 'sumRow', 'averageRow'],
        ],
        'tshirts' => [
             'class' => ActiveColumn::className(),
             'label' => 'T-shirts',
             'attribute' => 'tshirts',
             'behaviors' => ['sum', 'average', 'sumRow', 'averageRow'],
        ],
        'pants' => [
             'class' => ActiveColumn::className(),
             'label' => 'Pants',
             'attribute' => 'pants',
             'behaviors' => ['sum', 'average', 'sumRow', 'averageRow'],
        ],
        'total' => [
             'class' => TargetColumn::className(),
             'format' => 'number',
             'initialValue' => 0,
        ],
    ],
]);

$grid->startHead(/* $headOptions */);
$grid->head();
$grid->endHead();

$grid->startBody(/* $bodyOptions */);
$grid->body();
$grid->endBody();

$grid->startFooter(/* $footerOptions */);
$grid->footer();
$grid->behaviors->sum->printRow();
$grid->behaviors->average->printRow();
$grid->endFooter();

ActiveGridView::end();

It will require the following events:

begin, startHead, endHead,startBody, endBody,startFooter, head, body, footer, endFooter, beforeContent, afterContent, end very similar to the layout events. http://www.yiiframework.com/doc-2.0/guide-structure-views.html#creating-layouts

Insolita commented 9 years ago

Faryshta, interesting idea аs my example its https://github.com/Insolita/gridconcept (draft only)

Faryshta commented 9 years ago

@Insolita it looks very interesting, but i don't understand what any of those behaviors do :)

we agreee that the columns and behaviors should added with names so that they can be individually accesible later.

pavlm commented 9 years ago

I'am interested too in gridview extending. But i think there is a simple way with $layout placeholders. To enable custom placeholders in $layout little fix in ::renderSection can be made.

class GridViewExt extends GridView
{
    public function renderSection($name)
    {
        $html = parent::renderSection($name);
        if (!$html) {
            $renderMethod = 'render' . trim($name, '{}');
            if ($this->hasMethod($renderMethod)) {
                $html = $this->{$renderMethod}($name);
            }
        }
        return $html;
    }
}

Custom placeholder usage can be like this:

echo GridView::widget([
        'dataProvider' => $dataProvider,
        'columns' => $columns,
        'layout' => "{summary}\n{items}\n{pager}\n{actionsBar}",
        'as actionsBar' => [ // behavior with method renderActionsBar()
            'class' => ActionsBarBehavior::className(),
            ...
        ],
    ]);
klimov-paul commented 8 years ago

Merged into #7435