I have been through this. Let’s analize a simple project.
We have 3 tables in DB:
profile (
id INT PK,
name CHAR(30)
)
user (
id INT PK,
users_profile INT FK REFERENCES profile(id)
)
message (
id INT PK,
sender INT FK REFERENCES user(id),
receiver INT FK REFERENCES user(id),
)
We generate Yii project and model classes based on that DB tables.
We want to show all messages in tabular format including columns:
ID
Senders ID
Receivers ID
Senders Name
Receivers Name
All of these columns have to be sortable and provide search ability.
That is what we have to do:
Model classes User.php and Profile.php can stay as they were generated.
We have to mess up in Message.php.
- Add two new fields to our Message class:
public $sendersName;
public $receiversName;
- Modify rules to enable searching. We must add the two fields from previous step to safe/on search rule.
array('id, sender, receiver, sendersName, receiversName', 'safe', 'on'=>'search'),
- Check the names of Yii generated relations corresponding to sender and receiver. They should look like this:
'sender0' => array(self::BELONGS_TO, 'User', 'sender'),
'receiver0' => array(self::BELONGS_TO, 'User', 'receiver'),
- We can modify attribute labels:
public function attributeLabels()
{
return array(
'id' => 'ID',
'sender' => 'Sender',
'receiver' => 'Receiver',
);
}
Change to:
public function attributeLabels()
{
return array(
'id' => 'ID',
'sender' => 'Senders ID',
'receiver' => 'Receivers ID',
'sendersName' => 'Senders Name',
'receiverName' => 'Receivers Name',
);
}
- In Message::search() method:
We have to modify the $criteria inside search() method. Precisely $criteria->with property.
We must add every relation that will be used in our search. We will use these relations:
sender0
receiver0
These will give us two user objects. But to get names of sender and receiver we have to use User class relations. In my case
User class has these relations:
'messages' => array(self::HAS_MANY, 'Message', 'sender'),
'messages1' => array(self::HAS_MANY, 'Message', 'receiver'),
'usersProfile' => array(self::BELONGS_TO, 'Profile', 'users_profile'),
We are interested only in usersProfile relation, cause it will give us an object of Profile class which holds users name that we want to display.
So, we have to insert it to our $criteria->with property as well.
Ther is a catch. We can do it like this:
$criteria->with=array('sender0.usersProfile', 'receiver0.usersProfile');
But that would result in bad "Not unique table/alias" exception. So, I propose this solution:
$criteria->with=array('sender0.usersProfile'=>array('alias'=>'sendersProfile'), 'receiver0.usersProfile'=>array('alias'=>'receiversProfile'));
- Now that relations are set we can add two comparison expressions to enable search:
$criteria->compare('sendersProfile.name',$this->sendersName, true);
$criteria->compare('receiversProfile.name',$this->receiversName, true);
- Then we can add sort to our CActiveDataProviders constructor call to enable sorting:
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'sendersName'=>array( 'asc'=>'sendersProfile.name ASC', 'desc'=>'sendersProfile.name DESC' ),
'receiversName'=>array( 'asc'=>'receiversProfile.name ASC', 'desc'=>'receiversProfile.name DESC' ),
),
),
));
But, if we leave it like that we will see that now ‘ID’, ‘Senders ID’ and ‘Receivers ID’ are not sortable. We have to add them to our sort as well:
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'id',
'sender',
'receiver',
'sendersName'=>array(
'asc'=>'sendersProfile.name ASC',
'desc'=>'sendersProfile.name DESC'
),
'receiversName'=>array(
'asc'=>'receiversProfile.name ASC',
'desc'=>'receiversProfile.name DESC'
),
),
),
));
- In view just add CGridView:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'message-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'sender',
'receiver',
array(
'name'=>'sendersName',
'value'=>'$data->sender0->usersProfile->name',
),
array(
'name'=>'receiversName',
'value'=>'$data->receiver0->usersProfile->name',
),
array(
'class'=>'CButtonColumn',
),
),
)); ?>
And its all. I hope It helped someone. Also, Hi, everyone, it is my first post:)