jackhao
jackhao

Reputation: 3857

Yii DataProvider change the attributes of a column in each result

I'm using Yii's Dataprovider to output a bunch of users based on the column "points";

It works fine now but I have to add a feature so if the user is online, he gets an extra 300 points.

Say Jack has 100 points, Richmond has 300 points, However Jack is online, so Jack should rank higher than Richmond.

Here is my solution now:

$user=new Rank('search');
$user->unsetAttributes();
$user->category_id = $cid; 
$dataProvider = $user->search();
$iterator = new CDataProviderIterator($dataProvider);
foreach($iterator as $data) {

//check if online ,update points

}

However, this CDataProviderIterator seems change my pagination directly to the last page and I can't even switch page anymore. What should I do?

Thank you very much!


Here is the listview:

$this->widget('zii.widgets.CListView', array(
             'id'=>'userslist',
             'dataProvider'=>$dataProvider,
             'itemView'=>'_find',
         'ajaxUpdate'=>false,
             'template'=>'{items}<div class="clear"></div><div style="margin-right:10px;"><br /><br />{pager}</div>',
             'pagerCssClass'=>'right',
'sortableAttributes'=>array(
      //  'create_time'=>'Time',
    ), 
));

Updated codes in Rank.php model

$criteria->with = array('user');
$criteria->select = '*, (IF(user.lastaction > CURRENT_TIMESTAMP() - 1800, points+300, points)) as real_points';
$criteria->order = 'real_points DESC';

However, it throws me error:

Active record "Rank" is trying to select an invalid column "(IF(user.lastaction > CURRENT_TIMESTAMP() - 1800". Note, the column must exist in the table or be an expression with alias.

Upvotes: 0

Views: 1252

Answers (1)

driver_by
driver_by

Reputation: 1705

CDataProviderIterator iterates every dataprovider value, and stops at the end. I don't know all about this classes, but think the reason is in some internal iterator, that stops at the end of dataprovider after your foreach. Iterators are used when you need not load all data (for large amounts of data) but need to process each row.

To solve your problem, just process data in your view "_find". Add points there if online.

Or if you want place this logic only in the model (following MVC :) ), add method to your model:

public function getRealPoints() {
    return ($this->online) ? ($this->points + 300) : $this->points;
}

And you can use $user->realPoints to get points according to user online status

update: To order your list by "realPoints" you need to get it in your SQL. So use your code:

$user=new Rank('search');
$user->unsetAttributes();
$user->category_id = $cid; 
$dataProvider = $user->search();

and modify $user->search() function, by adding:

$criteria->select = '*, (IF(online='1', points+300, points)) as real_points';
$criteria->order = 'real_points DESC';

where online and points - your table columns.

Upvotes: 1

Related Questions