Mr Goobri
Mr Goobri

Reputation: 1469

Sort Cgridview By Custom Field

I'm aware that similar questions have been asked, sorry, but I can't for the life of me see what I'm doing wrong. Any help would be greatly appreciated. All I want to do is to add an extra column to a CGridView that displays a total of two values in the database.

These are the steps I've taken:

Database
User(forename, surname, part1, part2)

class User extends Controller:
    protected function getTotal($data,$row,$dataColumn){
            return $data->getAttribute('part1')+$data->getAttribute('part2');
    } 

    public function actionIndex(){
            $dataProvider=new CActiveDataProvider('User');
            $this->render('index',array(
                    'dataProvider'=>$dataProvider,
            ));
    }

class Stadium extends CActiveRecord:
    public function rules(){
            return array(
                    array('forename, surname', 'required'),
                    array('forename', 'surname', 'max'=>50),
                    array('part1, part2', 'numerical', 'integerOnly'=>true),

                    array('forename, surname, part1, part2, total', 'safe', 'on'=>'search'),
            );
    }

    public function attributeLabels()
    {
            return array(
                    'forename' => 'forename',
                    'surname' => 'surname',
                    'part1' => 'part1',
                    'part2' => 'part2',
                    'total' => array(
                            'asc'=>'part1 + part2',
                            'desc'=>'part1 + part2 desc',
                    ),
            );
    }

    public function search(){
            $criteria=new CDbCriteria;

            $criteria->compare('forename',$this->forename,true);
            $criteria->compare('surname',$this->surname,true);

            $criteria->compare('part1',$this->part1);
            $criteria->compare('part2',$this->part2);

            $criteria->compare('total',$this->part1 + $this->part2,true);

            $sort = new CSort();
            $sort->attributes = array(
                'total'=>array(
                    'asc'=>'part1 + part2 ASC',
                    'desc'=>'part1 + part2 DESC',
                ),
                '*',
            );

            return new CActiveDataProvider(User', array(
                    'criteria'=>$criteria,
                    'sort'=>$sort,
            ));
    }
}

view/User/index.php
    <?php $this->widget('zii.widgets.grid.CGridView', array(
                    'itemsCssClass'=>'table table-hover',
                    'dataProvider'=>$dataProvider,
                    'template'=>"{items}",
                    'columns'=>array(
                            array('name'=>'forename', 'header'=>'Forename'),
                            array('name'=>'surname', 'header'=>'Surname'),
                            array('name'=>'total', 'header'=>'Total', 'value'=>array($this, 'getTotal')),
                    ),
            )); ?>
<?php $this->endWidget();?>

Thanks a lot for any advice.

Upvotes: 1

Views: 1742

Answers (2)

Pitchinnate
Pitchinnate

Reputation: 7556

Solution: Ok here is what you need to do:

class Stadium extends CActiveRecord:
    public $total; //add this line

    //your rules should be fine

    //don't know if you need the asc and desc on attribute labels i just have one
    'total' => 'Total',

    $criteria->compare('total',$this->total); //change this line

    //i didn't use a Csort you might be able to but this is they way i did it
    return new CActiveDataProvider(User', array(
        'criteria'=>$criteria,
        'sort'=> array(
            'attributes' => array(
                'total'=>array(
                    'asc'=>'(part1 + part2) ASC',
                    'desc'=>'(part1 + part2) DESC',
                ),
                '*',
            ),
        ),
    ));

    //add this inside your model also
    public function afterFind() {
        parent::afterFind();
        $this->total = $this->part1+ $this->part2;
        return;
    }

Everything else in your model is fine. Then on your CGridView just change the one line:

array('name'=>'total', 'header'=>'Total'), //don't need to set value it is part of the model like other columns now

http://www.yiiframework.com/forum/index.php/topic/21114-create-now-model-variable/


Original Answer:

I believe if you are going to use a CSort object you need to add it to the CActiveDataProvider using setSort() or you don't have to create a CSort you can put it straight into DataProvider.

Option 1:

    $sort = new CSort();
    $sort->attributes = array(
        'total'=>array(
            'asc'=>'part1 + part2 ASC',
            'desc'=>'part1 + part2 DESC',
        ),
        '*',
    );

    $data = new CActiveDataProvider(User', array(
            'criteria'=>$criteria,
    ));
    $data->setSort($sort);
    return $data;

Option 2:

return new CActiveDataProvider(User', array(
    'criteria'=>$criteria,
    'sort'=> array(
        'attributes' => array(
            'total'=>array(
                'asc'=>'part1 + part2 ASC',
                'desc'=>'part1 + part2 DESC',
            ),
            '*',
        ),
    ),
));

This may help http://www.yiiframework.com/wiki/381/cgridview-clistview-and-cactivedataprovider/#hh11 http://www.yiiframework.com/doc/api/1.1/CDataProvider#setSort-detail

Upvotes: 1

Lajos Arpad
Lajos Arpad

Reputation: 76508

Pitchinnate's answer might help you, also, I've noticed a tendency from your part that you put commas where they shouldn't be present. For example

instead of:

        $sort->attributes = array(
            'total'=>array(
                'asc'=>'part1 + part2 ASC',
                'desc'=>'part1 + part2 DESC',
            ),
            '*',
        );

you need:

        $sort->attributes = array(
            'total'=>array(
                'asc'=>'part1 + part2 ASC',
                'desc'=>'part1 + part2 DESC'
            ),
            '*'
        );

you should get rid of all the commas put after the last element.

Upvotes: 0

Related Questions