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.
Related
So the problem is, that I have a view that will render a CGridView containing a count value. I had to make a custom CDbCriteria so that I could select the right infos. Now I can't display it in a CGridView.
Here is my controller action that builds the CActiveDataProvider:
public function actionListProducts(){
$criteria=new CDbCriteria;
$criteria->select = 'rp_product as product, count(rp_id) as cnt';
$criteria->group = 'product';
$dataProvider=new CActiveDataProvider('report', array( 'criteria'=>$criteria,
));
$this->render('listProducts',array(
'dataProvider'=>$dataProvider,
));
}
I am trying to display it in this CGridView:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'reports-grid',
'dataProvider'=>$dataProvider,
'columns'=>array(
'product',
'cnt'
),
));
I know the data is fetched properly because my CGridView has the right number of rows... What am I suppose to write in the 'columns' description?
Thank you
If you want to use the aliases product and cnt (var AS alias), you have to make a public property of it in the model Report.
Example:
Model extends CActiveRecord {
....
public $product;
public $cnt;
...
}
I've a standard Gii created admin view, which use a CGridView, and it's showing my user table data.
the problem is that user with name 'root' must NOT BE VISIBLE.
Is there a way to add a static where condition " ... and username !='root' " ?
admin.php [view]
'columns'=>array(
'id',
'username',
'password',
'realname',
'email',
.....
user.php [model]
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('username',$this->username,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('realname',$this->realname,true);
$criteria->compare('email',$this->email,true);
......
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
You can use CDbCriteria's addCondition like this:
$criteria->addCondition("username !='root'");
Your best option would be to use Yii scopes which are essentially a saved where clause (or other modification of your existing criteria) that you can apply all over your app and only need to change in one place if your criteria ends up changing later.
What makes them even cooler is that you can string them together with other scopes / criteria changes (from users in grids for instance) without having to keep track of what criteria clause is getting changed by what.
A few examples that might apply to your situation. In your controller you probably have something like this:
$users = User::model()->search()->findAll();
Asgaroth's answer answers what you were asking on the surface. But there is so much more you can do (and do easily) using scopes.
If you add the below to your user model:
class User extends CActiveRecord
{
......
public function scopes()
{
return array(
'active'=>array(
'condition'=>'active=1',
),
'isAdmin'=>array(
'condition'=>'isAdmin=1',
),
);
}
}
then you can retrieve active users (with your users' filters still applied) like this in your controller:
$users = User::model()->active()->search()->findAll();
Or you can retrieve all active admin users (without being filtered by your gridview criteria) like this:
$users = User::model()->active()->isAdmin()->findAll();
Default scopes are just an extension of the same idea:
class User extends CActiveRecord
{
public function defaultScope()
{
return array(
'condition'=>"username != 'root'",
);
}
}
If before your isAdmin scope would return the root user, applying the default scope will eliminate the root user from the models returned, as it applies to every User::model() query you make.
I am having very difficult time to select usernames of all posts in the blog demo given in Yii..
author is relation of post class with user...
$criteria = new CDbCriteria;
$criteria->with='author';
$criteria->select='author.username';
$dataProvider=new CActiveDataProvider('Post', array(
'criteria' => $criteria,
));
var_dump($dataProvider->getData());
Error:
Active record "Post" is trying to select an invalid column "author.username". Note, the column must exist in the table or be an expression with alias.
what with does is eager loading..that means the relation's data
will also loaded from database alongwith, and when when u'll call the
relation, there won't be a actual query..
What select does is it selects it from database and maps it to model
variable..
Now in your case what is happening is you're trying to write some relation's column in select, which will be there in select even without writing it, but as there is no corresponding variable to map this value yii is throwing an error..
So first thing if you need to username of auther in response, you can get it by relation calling, which won't be a database call, and u dont need to write a select..
And if u want to call the username as a part of the post model only u have got to declare it as a property in model, and then specify alias in select..
$criteria = new CDbCriteria;
$criteria->with='author';
$criteria->select='author.username as auther_username';
$dataProvider=new CActiveDataProvider('Post', array(
'criteria' => $criteria,
));
var_dump($dataProvider->getData());
and in your Post model declare..
public $auther_username;
Now it won't throw error, and you can access the username by both ways..$post->auther_username, and $post->auther->username
Try this:
$criteria = new CDbCriteria;
$criteria->with=array('author'=>array('select'=>'username'));
// you can still select Post table columns here
$criteria->select='post_content';
$dataProvider=new CActiveDataProvider('Post', array(
'criteria' => $criteria,
));
var_dump($dataProvider->getData());
Try this:
$criteria = new CDbCriteria;
$criteria->with=array('author'=>array('select'=>'username'));
$dataProvider=new CActiveDataProvider('Post', array(
'criteria' => $criteria,
));
var_dump($dataProvider->getData());
Source: CActiveRecord.with
In order to customize the options on the fly, we should pass an array
parameter to the with() method. The array keys are relation names, and
the array values are the corresponding query options.
I would like to return selected values to the CGridView (similar to IN query) using the search function that is generated by Yii.To elaborate further let me use the example below:
Here I return values of the based on the value '34455' (fk_recordid)
public function search()
{
$fk_recordid = '34455';
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id,true);
$criteria->compare('fk_recordid',$fk_recordid,true);
$criteria->compare('babypid',$this->babypid);
$criteria->compare('babysbn',$this->babysbn);
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
));
}
How would I change this code to widen the fk_recordid criteria i.e return records based on several values such as '34455','47859','78956' .....
Instead of compare() like you have:
$fk_recordid = '34455';
$criteria->compare('fk_recordid',$fk_recordid,true);
You could use addInCondition() like so:
$myRecordIds = array('34455','47859','78956');
$criteria->addInCondition('fk_recordid',$myRecordIds);
I don't know how you are passing in all of these record ids from the CGridView to the search() function, but once you have them addInCondition() will work. I hope this helps!
Please consider this:
class User extends CActiveRecord
{
...
public function relations()
{
return array(
...
'articleCount' => array(self::STAT, 'Article', 'userid'),
...
);
}
...
}
Now, I need to create a $dataProvider = new CActiveDataProvider(...) to feed a CListView widget to which I want add articleCount to the property sortableAttributes so that I can sort User records according to the number of articles the user is the author for.
What are the most convenient method? what are the other alternatives?
Well, it took me a while, but I finally got it figured out. ;)
First, make sure you still have the same STAT relation you mention in your question.
Then, in your search() method where you are building your CDbCriteria for the CActiveDataProvider, do something like this:
public function search() {
$criteria=new CDbCriteria;
$criteria->select = 't.*, IFNULL( count(article.id), 0) as articleCount';
$criteria->join = 'LEFT JOIN article ON article.userid = t.id';
$criteria->group = 't.id';
// other $criteria->compare conditions
$sort = new CSort();
$sort->attributes = array(
'articleCount'=>array(
'asc'=>'articleCountASC',
'desc'=>'articleCountDESC',
),
'*', // add all of the other columns as sortable
);
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
'sort'=>$sort,
'pagination'=> array(
'pageSize'=>20,
),
));
}
Then, in your View where you output your CGridView, do this like so:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'columns'=>array(
'articleCount',
// other columns here
)
)); ?>
This works, I tested it (although I did not use the exact same names, like 'article', but the basic idea should work :) I did add some bonus features so it works better (like the IFNULL magic) but most of the credit goes to this Yii forum post:
http://www.yiiframework.com/forum/index.php?/topic/7061-csort-and-selfstat-to-sort-by-count/
I hope this helps! They should add better support for this though, so you don't need to make these tricky SELECT statements. Seems like something that should 'just work', I would file an 'enhancement' request in the Yii bug tracker.