You are viewing revision #4 of this wiki article.
This is the latest version of this article.
You may want to see the changes made in this revision.
In this wiki I will show how could use a CSqlDataProvider in CGridView with specific features
In your controller/action
//a sample query but you could use more complex than it
$sql = 'SELECT DISTINCT T1.id AS MAIN_ID,T2.title AS title,T3.type AS type FROM T1 INNER JOIN T2 ON T1.id=T2.t1_id INNER JOIN T3 ON T2.id=T3.t2_id';
$rawData = Yii::app()->db->createCommand($sql); //or use ->queryAll(); in CArrayDataProvider
$count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM (' . $sql . ') as count_alias')->queryScalar(); //the count
$model = new CSqlDataProvider($rawData, array( //or $model=new CArrayDataProvider($rawData, array(... //using with querAll...
'keyField' => 'MAIN_ID',
'totalItemCount' => $count,
//if the command above use PDO parameters
//'params'=>array(
//':param'=>$param,
//),
'sort' => array(
'attributes' => array(
'MAIN_ID','title', 'type'
),
'defaultOrder' => array(
'MAIN_ID' => CSort::SORT_ASC, //default sort value
),
),
'pagination' => array(
'pageSize' => 10,
),
));
$this->render('anActionView', array(
'model' => $model,
));
In your view file (anActionView.php)
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'a-grid-id',
'dataProvider' => $model,
'ajaxUpdate' => true, //false if you want to reload aentire page (useful if sorting has an effect to other widgets)
'filter' => null, //if not exist search filters
'columns' => array(
array(
'header' => 'The id',
'name' => 'MAIN_ID',
//'value'=>'$data["MAIN_ID"]', //in the case we want something custom
),
array(
'header' => 'title',
'name' => 'title',
//'value'=>'$data["title"]', //in the case we want something custom
),
'type', //just use it in default way (but still we could use array(header,name)... )
array( //we have to change the default url of the button(s)(Yii by default use $data->id.. but $data in our case is an array...)
'class' => 'CButtonColumn',
'template' => '{delete}',
'buttons' => array(
'delete' => array('url' => '$this->grid->controller->createUrl("delete",array("id"=>$data["MAIN_ID"]))'),
),
),
),
));
That's it ;)
$main???
'dataProvider' => $main, What is $main here??
//'value'=>'$data["MAIN_ID"]', //in the case we want something custom , What is $data here??
RE: #16829
it was a typo
'dataProvider' => $model
'$data' is Yii-CGridview internal iterator that takes each item of the $model.
if you want see more details about all the data of the CSqlDataProvider You could type
Use of $rawdata
$model = new CSqlDataProvider($rawData, array()
Why use $rawData here can't we use $sql? Also I don't think you need this line
RE: #16831
Is the same thing
$rawData = Yii::app()->db->createCommand($sql); //or use ->queryAll(); in CArrayDataProvider
Yii::app()->db->createCommand($sql) does not return array of data.
I named it '$rawdata' for alternative CArrayDataProvider code
want to know if the counting is a efficient way
SELECT COUNT(*) FROM (' . $sql . ') as count_alias
This way using a subquery , so just want to know whether this is a efficient way .
RE: #16872
the main query returns all the specific rows.
but in CSqlDataProvider (when pagination is used), limits concatenates in the main in the final query (for example select * from... limit 0,10). In this case CSqlDataProvider cannot calculate the number of pages pagination (and the current page), so you have to set the totalItemCount explicity.
So
$count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM (' . $sql . ') as count_alias')->queryScalar(); //the count
using to calculates the total counts
If anyone knows a more efficient way, please inform us.
now i using another way to calculate the count
/** * @static * @param $sql * @param array $params * @param CDbConnection $db * @return int|mixed * @warning id the sql string has "UNION" and is in the sub query you 'd better * not use this function ! * if the sql not contain "UNION" it will work well ! */ static public function countBySql($sql, $params = array(), CDbConnection $db = null) { $parts = explode('UNION', $sql); if (count($parts) > 1) { $count = 0; foreach ($parts as $selectSql) { $count += self::countBySql($selectSql, $params); } return $count; } else { $selectStr = trim($sql); // $selectStr = substr_replace($selectStr, ' COUNT(*) ', 6, stripos($selectStr, 'FROM') - 6); $selectStr = preg_replace('~ORDER\s+BY.*?$~sDi', '', $selectStr); $db = ($db == null) ? Yii::app()->db : $db; return $db->createCommand($selectStr)->queryScalar($params); } }
note : if your query string contain more then one union clause or union clause exists in subquery , plz do not use this
RE: #16875
Thanks yiqing95,
Your function it could be used in most cases, reducing the resource consumption of the sql execution.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.