I am having difficulty getting the filtering to work in CGridView for relational fields from another model.
URL Reference: Yii 1.1: Searching and sorting by related model in CGridView
I follow the codes and it seems to be returning me the inputs from the other model. Everything looks fine but unfortunately, the filter is not working.
On Search, it will display a quick load icon but failed to filter accordingly. Upon checking further, I noticed the input is wrong. I am using Google Inspect Element and noticed the following:
<input name="User[full_name]" type="text">
I am using User model, relational to Biodata. Shouldn't it be Biodata[full_name]? If this is, where should I be looking at the codes?
Thank you. :D
Filtering and sorting in CGridView widget can be done in few steps:
1. Add virtual field to your User model. It will be used to create column in CGridView; it also needed for proper filtering and sorting:
class User extends CActiveRecord
{
public $bioFullName;
//...
}
2. Modify search() function in your User model. You need to add array parameter to this function and add to $criteria object in this method connection with related model. To add sorting of related attribute, you also need to modify returned CActiveDataProvider. See what happens below:
public function search($params = array()) // <-- new parameter that handling params for searching
{
$criteria = new CDbCriteria($param);
$criteria->with = array('biodata'); //add relation with Biodata to $criteria object
// ... existing $criteria conditions
$criteria->addSearchCondition('biodata.full_name', $this->bioFullName, true, 'AND'); // add comparison of biodata.full_name
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
// ...
'sort'=>array(
'attributes'=>array(
'bioFullName'=>array( // <-- sorting of related field
'asc'=>'biodata.full_name ASC',
'desc'=>'biodata.full_name DESC',
),
'*',
),
),
));
}
3. Adjust CGridView widget in your view to show related column. In columns array of widget configuration add column named like virtual field from model (bioFullName):
<?php
$this->widget('zii.widgets.grid.CGridView', array(
// ... other widget configuration options
'columns'=>array(
// ... other columns
'bioFullName'=>array(
'name'=>'bioFullName', // <-- name of virtual model field
'value'=>'$data->biodata->full_name', // <-- getting field value from relation
'header'=>'Full name', // <-- CGridView column header
),
// ... other columns
),
));
?>
I use a search symptoms form and I pass off the symptomCode to my diseaseController
both symptoms and diseases have model classes, but the table connecting the 2 does not.
I use this query to find all the diseases that have the specific symptom
$diseaseCodes = Yii::app()->db->createCommand()
->select ('ICD10')
->from('tbl_disease')
->join('tbl_symptom_disease', 'tbl_disease.ICD10=tbl_symptom_disease.diseaseCode')
->where('symptomCode=:symptomCode',
array(':symptomCode'=>$_GET['symptomCode']))
->queryAll();
Now I want to know how I can use this to populate a dataprovider to populate a gridview
One idea I had was to create a custom model function
public function queryResultSearch($diseaseArray)
{
$criteria=new CDbCriteria;
$criteria->compare('ICD10',$diseaseArray,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
And use this to render yii's admin action (for disease models), but I can't get it to work because probably my entire way at going at this is wrong.
Can someone help me please? How to use a mysql query result to populate an activedataprovider object.
Thank you for your time
In your controller action you can try this:
$model=new ModelName('search');
$model->unsetAttributes();
if(isset($_GET['ModelName']))
$model->attributes=$_GET['ModelName'];
$diseaseCodes = Yii::app()->db->createCommand()
->select ('ICD10')
->from('tbl_disease')
->join('tbl_symptom_disease', 'tbl_disease.ICD10=tbl_symptom_disease.diseaseCode')
->where('symptomCode=:symptomCode',
array(':symptomCode'=>$_GET['symptomCode']))
->queryAll();
$diseaseArray=array();
foreach ($diseaseCodes as $dc) {
$diseaseArray[]=$dc['ICD10'];
}
$criteria=new CDbCriteria;
$criteria->compare('ICD10',$diseaseArray,true);
$dataProvider = new CActiveDataProvider(get_class($model),array('criteria'=>$criteria));
$dataProvider->criteria->mergeWith($model->search()->criteria);
$this->render('view',array(
'model'=>$this->loadModel($id),
'dataProvider'=> $dataProvider,
));
You are going to want to use CArrayDataProvider. This is less than ideal.. and you will have to implement all your sorting and pagination on your own
You are much better off using a model and implementing similar to
public function queryResultSearch($diseaseArray)
{
$criteria=new CDbCriteria;
$criteria->compare('ICD10',$diseaseArray,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
To make your first model I would personally use Gii.
In my Web Application I have three models. Namely- items,Manufacturers,items_manufacturers
This is the query I need to perform
SELECT items.id,item_desc,manufacturers.id,manufacturers.name FROM items_manufacturers,items,manufacturers WHERE items_manufacturers.item_id=item.id AND items_manufacturers.manufacturer_id=manufacturers.id
The relation between the models is
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'item' => array(self::BELONGS_TO, 'Items', 'item_id'),
'manufacturer' => array(self::BELONGS_TO, 'Manufacturers', 'manufacturer_id'),
'itemsManufacturersLocations' => array(self::HAS_MANY, 'ItemsManufacturersLocations', 'items_manufacturer_id'),
);
}
I am unable to write this query using the conventions in Yii framework.
This is what I tried
$im=new CDbCriteria ;
$im->with= array(
'items_manufacturers.item_id'
'items_manufacturers.manufacturer_id'
'items.item_desc'
'manufacturers.manufacturer_name'
'condition'=>'items_manufacturers.manufacturer_id=manufacturers.id
items_manufacturer.item_id=items.id'
);
))->findAll();
Any body kindly help me with this, since I am new to this framework.I am stuck up with this.I tried this in the items_manufacturers Controller.
You're assigning 'with' property with db columns, while you should do something like:
$im = new CDbCriteria;
$im->with = array('items','manufacturers'); // you put 'relation names' here, not db columns
$imf = ItemsManufacturers::model()->findAll($im);
You could do this without criteria:
$imf = ItemsManufacturers::model()->with('items','manufacturers')->findAll();
I am using Yii framework. i am wonder how i can get records from multiple tables i did research but couldn't find any usefull link i am using following code for this please let me know where i am missing
my model Task.php
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'prj_user' => array(self::BELONGS_TO, 'User', 'id'),
);
}
model User.php
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
array('task', self::HAS_MANY, 'Task','project_id')
);
}
and this is my main controller
$criteria = new CDbCriteria;
$criteria->compare('t.id', 1);
$criteria->with = array( 'prj_user' => array('select' => 'username,title,roles', 'joinType'=>'inner join'));
$rows = Task::model()->findAll( $criteria );
but still i am getting columns only from task table but i need more three columns from users table please help me
Let Yii worry about joining your tables. Your relations looks fine so you should be able to access them directly
For example, what does this return?
foreach ($rows as $task)
{
if ( isset($task->prj_user) )
echo $task->prj_user->username . "<br>";
}
Or this?
this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>new CActiveDataProvider('Task'),
'columns'=>array(
'id',
'prj_user.username',
'prj_user.title',
'prj_user.roles',
)
));
->with() is used for eager loading, so at this point you probably don't need it. In fact, unless I misread you completely, you can remove your criteria all together.
Yii 1.1 application development Cookbook explain a method for using data from related Active Record Models for searching the related models as well. This method is explained in page number 193 and 194. i have tried to integrate this method in to my application but it does not work. could anybody explain me whether this feature is still available in Yii framework version 1.1.8
At this location also i could find comments for searching data form related active record models. But it also does not work.
http://www.yiiframework.com/doc/api/1.1/CDbCriteria
I have order table and user table
Order table and User table has One to many Relation.
User has many orders and order has exactly one user.
So , i am editing following CDbCriterial to include user tables name and email field in to Order tables search entries.
Order table has following relations
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'comments' => array(self::HAS_MANY, 'Comment', 'order_id'),
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
'orderstatus' => array(self::BELONGS_TO, 'Orderstatus', 'orderstatus_id'),
'commentCount' => array(self::STAT, 'Comment' , 'order_id')
);
}
This is the search/filter conditions with user table's name filed included
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('order_create_date',$this->order_create_date,true);
$criteria->compare('price',$this->price,true);
$criteria->compare('bank_account_number',$this->bank_account_number,true);
$criteria->compare('hardwaredetail_Id',$this->hardwaredetail_Id);
$criteria->compare('user_id',$this->user_id);
$criteria->compare('order_update_date',$this->order_update_date,true);
$criteria->compare('is_received',$this->is_received);
$criteria->compare('order_received_date',$this->order_received_date,true);
$criteria->compare('is_notify_by_email',$this->is_notify_by_email);
$criteria->compare('warehouse_offered_price',$this->warehouse_offered_price,true);
$criteria->compare('warehouse_offered_price_date',$this->warehouse_offered_price_date,true);
$criteria->compare('orderstatus_id',$this->orderstatus_id);
$criteria->together = true;
$criteria->with = array('user');
$criteria->compare('user.name',$this->user,true);
//$criteria->compare('user.name',$this->user->name);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
and Order admin page is edited to display the name filed as follows
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'order-grid',
'dataProvider'=>$model->search(),
//'filter'=>$model,
'columns'=>array(
'id',
'order_create_date',
'price',
'bank_account_number',
array(
'name'=>'user',
'value'=>'$data->user->name'
),
),
));
Error message returned
After solving the id column ambiguity problem by applying the solution that thaddeusmt gave i have faced with the following error message.
Thanks in advance for any help
I could find the answer. This is all i did.
Following are the two tables i have. Order and User
I have Order/Admin page, Default generated code provide searching order table data only. i want to relate user tables name field in the search criteria.
This is the initial look of the search page.
I want to integrated user name filed from other table in to this search. then final look will be as follows.
so these are the steps i did.
first in the Order model i have following relations
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
);
}
This is generated by Yii framework , i did nothing :)
Then , i changed the search method as follows
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('t.order_create_date',$this->order_create_date,true);
$criteria->compare('t.price',$this->price,true);
$criteria->compare('t.bank_account_number',$this->bank_account_number,true);
$criteria->compare('t.hardwaredetail_Id',$this->hardwaredetail_Id);
//$criteria->compare('user_id',$this->user_id);
$criteria->compare('t.order_update_date',$this->order_update_date,true);
$criteria->compare('t.is_received',$this->is_received);
$criteria->compare('t.order_received_date',$this->order_received_date,true);
$criteria->compare('t.is_notify_by_email',$this->is_notify_by_email);
$criteria->compare('t.warehouse_offered_price',$this->warehouse_offered_price,true);
$criteria->compare('t.warehouse_offered_price_date',$this->warehouse_offered_price_date,true);
$criteria->compare('t.orderstatus_id',$this->orderstatus_id);
$criteria->together = true;
$criteria->compare('t.id',$this->id,true);
$criteria->with = array('user');
$criteria->compare('name',$this->user,true,"OR");
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
it is important to put t in-front of the t if your Order table primary key field if both have save name. in my case it is id and id, so i had to put t.
Other thing is the order of the elements
$criterial->togeter = true; should come before the relational elements.
then u updated to rules method in Order table. i added user filed and name filed to safe attributes.
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
//array(' orderstatus_id', 'required'),
array('hardwaredetail_Id, user_id, is_received, is_notify_by_email, orderstatus_id', 'numerical', 'integerOnly'=>true),
array('price, warehouse_offered_price', 'length', 'max'=>10),
array('bank_account_number', 'length', 'max'=>100),
array('order_create_date, order_update_date, order_received_date, warehouse_offered_price_date, user,name', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, order_create_date, price, bank_account_number, hardwaredetail_Id, user_id, order_update_date, is_received, order_received_date, is_notify_by_email, warehouse_offered_price, warehouse_offered_price_date, orderstatus_id', 'safe', 'on'=>'search'),
);
}
Finally update your UI code.
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'order-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'order_create_date',
'price',
'bank_account_number',
array(
'name'=>'user',
'value'=>'$data->user->name'
)
)); ?>
i updated the order admin with the
array(
'name'=>'user',
'value'=>'$data->user->name'
)
That is what i did and it worked for me. ask me if you need any help. Thanks every one looking in to this issue.
It looks like both the user and order have columns named id. And your criteria uses them both in the WHERE clause, which is giving the "ambiguous" mySql error message.
When using with criteria (which does a SQL JOIN of the tables), if two of your tables have columns with the same name you need to use the mySql "dot" prefix on conditions, like so:
$criteria->compare('t.id',$this->id); // the default table prefix in Yii is "t"
When I JOIN a table using $criteria->with I prefix all of the column names (in my compare and condition criteria, etc)., like so:
$criteria->compare('t.id',$this->id); // t
$criteria->compare('t.order_create_date',$this->order_create_date,true); // t
$criteria->with = array('user');
$criteria->compare('user.name',$this->user_id,true); // user (the filter will set user_id)
Your gridview will need to look like this:
array(
'name'=>'user_id',
'header'=>'User',
'sortable'=>false,
'value'=>'$data->user->name'
),
Also, I think there is a larger problem, as you point out with your edit:
Your search function is set up like this: user.name',$this->user - but $this->user is going to return the current user object via the relation, not the search criteria. The column filter will set the user_id, property.
EDIT: Nope, you can $this->user as your column name so long as you set it as a safe attribute.
The way I am getting around this is shown in more detail here:
Search in BELONGS_TO model column with CGridView, Yii
Sorting will not work with that though - just the filtering.
Here is good post in the Yii forum that might give you more clues, too:
http://www.yiiframework.com/forum/index.php?/topic/9083-search-filter-of-a-relations-field-through-cgridview/
Sadly, sorting and filter CGridViews on relations is not really default functionality. YOu can easily display related info with a column name like user.name, but it won't sort or filter. Good luck!