Yii, CGridView: filtering and sorting count column from related tables - yii

I have 3 tables: productions, chunks (production may have a lot of chunks, so chunks contains production_id column) and chunk_designers (chunk may have a lot of designers, so chunk_designers has a column chunk_id).
I have to render data from productions in CGridView and add a column: count of chunks (for every production item in table), which are not assigned to any chunk. In other words:
SELECT COUNT(*) FROM `chunks`
left JOIN `chunk_designers`
ON chunks.id = chunk_designers.chunk_id
WHERE production_id = 520 AND chunk_id IS null
...where 520 - dynamic value for every row, productions.id.
ChunkController action:
function actionProductionList() {
$model = new Productions('search');
$model->unsetAttributes(); // clear any default values
$dataProvider = $model->search($_GET);
$dataProvider->criteria->order = 'start_time DESC';
$this->render('production_list', array(
'provider' => $dataProvider,
'model' => $model,
));
}
Model Productions:
class Productions extends AppModel {
....
public $unassignedBlocksCount;
....
public function rules() {
return array(
array('unassignedBlocksCount, id, ...', 'safe'),
array('unassignedBlocksCount, id, ...', 'safe', 'on'=>'search'),
);
}
//in search() I added:
$criteria->compare('unassignedBlocksCount', $this->unassignedBlocksCount, true);
}
And in view:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'menu-grid',
'dataProvider' => $provider,
'filter' => $model,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'unassignedBlocksCount',
'value' => 'Chunks::getUnassignedBlocksCount($data->id)'
),
...
Column data is rendered fine, but when I try to filter it, I get the following error: unknown column unassignedBlocksCount in where clause.
I tried to write in search() method in Productions model:
// subquery to retrieve the count of posts
$count_sql = "(SELECT COUNT(*) FROM `chunks` "
. "LEFT JOIN `chunk_designers` "
. "ON chunks.id = chunk_designers.chunk_id "
. "WHERE production_id = 520 AND chunk_id IS NULL)";
// select
$criteria->select = array(
'*',
$count_sql . " as unassignedBlocksCount",
);
And just added unassignedBlocksCount element in columns in view.
But I still get the same error, when filter, and also problem is that I don't know, how to get production_id in $count_sql dynamically, depending on every table row (that's why in every row for that column value is 1, because it's correct value for production_id = 520).
So, my question is: how to get sortable and filterable column in CGridView, which is calculated (by COUNT()) from data in other tables? Thanks in advance.

Related

How to hide a column in yii

I want to hide a column in yii based on a condition. I have used a function in model. but visible functionality is not working in this column.
$this->widget('zii.widgets.grid.CGridview', array(
'id'=>'gridview',
'dataProvider'=>$dp,
'columns'=>array(
array(
'header' => 'Entries',
'value' => '$data->entry_name'
),
array(
'name' => 'value',
'value' => '$data->entry_name',
'visible'=>'$data->show()',
'type'=>'raw'
),
)
)
);
function in Model
public function show()
{
.........
return 1 or 0;
}
but it not working. Please help
I don't see a condition anywhere yet. You should use a comparison operator like return $this->attribute !== null; in your show function. Which returns true if attribute contains some value. Or if you want to do it on random you can return rand(0,1) == 1;.

Yii1 CGridView - SUM of Custom Column Value in footer

I want Sum of a custom column value in footer
GridView Code
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'booking-grid',
'dataProvider'=>$model->search(),
'columns'=>array(
array(
'name'=>'name',
'header'=>'User Name',
'value'=>'$data->booking_id',
'filter'=>false,
'footer'=>'Total',
'footerHtmlOptions'=>array('class'=>'grid-footer'),
),
array(
'name'=>'id',
'header'=>'User Fee',
'value'=> array($model,'GetUserFee'),
'filter'=>false,
'footer'=>'' . $model->getTotal($model->search()->getData(), 'id'),
'footerHtmlOptions'=>array('class'=>'grid-footer'),
),
),
));
Get Total
public function getTotal($records,$colName){
$total = 0.0;
if(count($records) > 0){
foreach ($records as $record) {
$total += $record->$colName;
}
}
return number_format($total,2);
}
Second column value are calculate user fee.
In footer sum of User Fee values get the wrong sum. It gives the sum of user ids. and id is table column name.
How can I get the sum of User fee column values
Instead of using a literal representation of id, try using the $data variable created by CGridView, which actually IS the current record from the $model currently being processed in each CGridView iteration.
Your code would then be:
array(
'name'=>'id',
'header' => 'User Fee',
'type' => 'raw',
'value' => '$data->id',
'filter' => false,
'footer' => '$model->getTotal($data)',
'footerHtmlOptions' => array('class'=>'grid-footer'),
),
Notice the value of the type attribute is set to raw.
You can even use a PHP function and pass it the $data variable, like so:
array(
'name'=>'id',
'header' => 'User Fee',
'type' => 'raw',
'value' => function ($data) { ... handle $data how you like ... }
'filter' => false,
'footer' => '$model->getTotal($data)',
'footerHtmlOptions' => array('class'=>'grid-footer'),
),
For more information check out special variables in Yii

Problems returning result of CDbCriteria based query

I have a query as follows
$criteria1 = new CDbCriteria();
$criteria1->condition = 'id = 1';
$modelA=Table1::model()->find($criteria1);
I can pass it to a view and return the title and entry
$this->widget('bootstrap.widgets.TbBox', array(
title' => $modelA['title'],
'content' => $modelA['entry'] ));
Now I'd like to return a range of entries
$criteria2 = new CDbCriteria();
$criteria2->condition = 'id > 7';
$modelB=Table1::model()->findAll($criteria2);
(btw : I'm following a form as laid out here). I was expecting to be able to read the resulting array of values out as below, but ['title'] is now being seen as a undefined index (obviously I'm expecting to read this out in a loop but you get the point)
$this->widget('bootstrap.widgets.TbBox', array(
'title' => $modelB['title'][0],
'content' => $modelB['entry'][0]));
Where am I going wrong?
Thanks
No, the indexes should be specified in the different order: the number of a specific element first, then the name of the property. Additionally, it's better (=cleaner) to name the result of findAll so it'll show you (and any other reader) that it's a collection, not a single model:
$models = Table1::model()->findAll($criteria2);
// ...
$this->widget('bootstrap.widgets.TbBox', array(
'title' => $models[0]['title']
//...
));
But even that's not necessary if you use foreach (and you probably will):
foreach ($models as $model):
// ...
$this->widget('some.name', array(
'title' => $model['title']
);
endforeach;

Dataprovider to EExcelView

lets say i have a table named
cars{
'id','name','brand_id',
}
and another table
brand{
'id','brand_name',
}
I have a situation that i want to generate an Excel report with the following attributes.
'name','brand_name' i.e. SELECT cars.name, brand.brand_name FROM cars INNER JOIN on brand WHERE cars.brand_id = brand.id
So i created a dataprovider like this:
$sql = "SELECT cars.name, brand.brand_name FROM cars INNER JOIN brand on cars.brand_id = brand.id";
$result = Yii::app()->db->createCommand($sql)->queryAll();
$this->render('doc', array('dataprovider' => $result));
Now i want to generate Excel file with result as a dataProvider so i write the following code:
// lets say i am doing this in view page named doc.php
$factory = new CWidgetFactory();
Yii::import('ext.eexcelview.EExcelView',true);
$widget = $factory->createWidget($this,'EExcelView', array(
'dataProvider'=>$dataprovider->search(),
'grid_mode'=>'export',
'title'=>'Title',
'creator'=>'TNC',
'autoWidth'=>false,
'filename'=>'Report.xlsx',
'stream'=>false,
'disablePaging'=>false,
'exportType'=>'Excel2007',
'columns'=>array(
'name',
'brand_name',),
'showTableOnEmpty' => false,
));
$widget->init();
$widget->run();
I have included all the extensions that i have to.. This code is working when i fed the dataProvider field with a single table entry .
But the situation arises when i include multiple tables.
These lines don't actually make a dataprovider:
$result = Yii::app()->db->createCommand($sql)->queryAll();
$this->render('doc', array('dataprovider' => $result));
You'll want to do something like the following:
$dataprovider = new CSqlDataProvider($sql, array(
'pagination'=>false,
);
$this->render('doc', array('dataprovider' => $dataprover);
More info here: http://www.yiiframework.com/doc/api/1.1/CSqlDataProvider
This works for 2 tables, dont know works for more than 2 or not.
$dataProvider = new CArrayDataProvider($dataprovider, array('id' => 'brand', 'sort' => array('attributes' => array('brand_name', ), ), 'pagination' => false));
$this -> render('doc', array('dataprovider' => $dataProvider,));

CGridView with relations, ID filter doesn't work `Integrity constraint violation`

I'm trying to make a cgridview that can filter data from relations table. This is my first time with CGridView and I just can't get it to work. Help is appreciated.
I have 2 problems. first: i have managed to get a dropdown filter of my users (avtor, relation in Novica), but when I choose one, it always returns this: "No results found.".
second: When I try to filter with Novica.ID, i get this error: (filtering with other columsn works great)
Error 500: CDbException CDbCommand failed to execute the
SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1052
Column 'id' in where clause is ambiguous. The SQL statement executed
was: SELECT COUNT(*) FROM novica t LEFT OUTER JOIN uporabnik
avtor ON (t.uporabnik_id=avtor.id) WHERE ((uporabnik_id =
:id) AND (id=:ycp0))
(C:\xampp\htdocs\PEF\framework\db\CDbCommand.php:528)0
C:\xampp\htdocs\PEF\framework\db\CDbCommand.php(425):
CDbCommand->queryInternal('fetchColumn', 0, Array) 1
C:\xampp\htdocs\PEF\framework\db\ar\CActiveFinder.php(762):
CDbCommand->queryScalar() 2
C:\xampp\htdocs\PEF\framework\db\ar\CActiveFinder.php(155):
CJoinElement->count(Object(CDbCriteria)) 3
C:\xampp\htdocs\PEF\framework\db\ar\CActiveRecord.php(1540):
CActiveFinder->count(Object(CDbCriteria)) 4
C:\xampp\htdocs\PEF\framework\web\CActiveDataProvider.php(179):
CActiveRecord->count(Object(CDbCriteria)) 5
C:\xampp\htdocs\PEF\framework\web\CDataProvider.php(193):
CActiveDataProvider->calculateTotalItemCount() 6
C:\xampp\htdocs\PEF\framework\web\CActiveDataProvider.php(129):
CDataProvider->getTotalItemCount() 7
C:\xampp\htdocs\PEF\framework\web\CDataProvider.php(137):
CActiveDataProvider->fetchData() 8
C:\xampp\htdocs\PEF\framework\zii\widgets\CBaseListView.php(105):
CDataProvider->getData() 9
C:\xampp\htdocs\PEF\framework\zii\widgets\grid\CGridView.php(269):
CBaseListView->init() 10
C:\xampp\htdocs\PEF\framework\web\CBaseController.php(148):
CGridView->init() 11
C:\xampp\htdocs\PEF\framework\web\CBaseController.php(173):
CBaseController->createWidget('zii.widgets.gri...', Array) 12
C:\xampp\htdocs\PEF\protected\views\adminNovica\index.php(28):
CBaseController->widget('zii.widgets.gri...', Array) 13
C:\xampp\htdocs\PEF\framework\web\CBaseController.php(127):
require('C:\xampp\htdocs...') 14
C:\xampp\htdocs\PEF\framework\web\CBaseController.php(96):
CBaseController->renderInternal('C:\xampp\htdocs...', Array, true) 15
C:\xampp\htdocs\PEF\framework\web\CController.php(870):
CBaseController->renderFile('C:\xampp\htdocs...', Array, true) 16
C:\xampp\htdocs\PEF\protected\controllers\AdminNovicaController.php(19):
CController->renderPartial('index', Array) 17
C:\xampp\htdocs\PEF\framework\web\actions\CInlineAction.php(50):
AdminNovicaController->actionIndex() 18
C:\xampp\htdocs\PEF\framework\web\CController.php(309):
CInlineAction->runWithParams(Array) 19
C:\xampp\htdocs\PEF\framework\web\CController.php(287):
CController->runAction(Object(CInlineAction)) 20
C:\xampp\htdocs\PEF\framework\web\CController.php(266):
CController->runActionWithFilters(Object(CInlineAction), Array) 21
C:\xampp\htdocs\PEF\framework\web\CWebApplication.php(276):
CController->run('') 22
C:\xampp\htdocs\PEF\framework\web\CWebApplication.php(135):
CWebApplication->runController('adminnovica') 23
C:\xampp\htdocs\PEF\framework\base\CApplication.php(162):
CWebApplication->processRequest() 24
C:\xampp\htdocs\PEF\index.php(13): CApplication->run() 25 {main}
These are my tables:
Models:
Novica (eng: News)
public function relations() {
return array(
'uporabnik' => array(self::BELONGS_TO, 'DostopNovica', 'uporabnik_id'),
'avtor' => array(self::BELONGS_TO, 'Uporabnik', 'uporabnik_id'),
);
}
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id);
$criteria->with = 'avtor';
$criteria->compare('naslov', $this->naslov, true);
$criteria->compare('datum', $this->datum, true);
$criteria->compare('avtor.upime', $this->uporabnik_id, true); //avtor.upime (eng. author.username)
return new CActiveDataProvider(get_class($this), array(
'criteria' => $criteria,
'sort' => array(
'defaultOrder' => 'datum DESC', //date
),
'pagination' => array(
'pageSize' => 5
),
));
}
Action:
public function actionIndex() {
$model = new Novica('search');
if (isset($_GET['Novica']))
$model->attributes = $_GET['Novica'];
$params = array(
'model' => $model,
);
if (!isset($_GET['ajax']))
$this->render('index', $params);
else
$this->renderPartial('index', $params);
}
CGridView:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array('id',
array('name' => 'datum',
'value' => 'date("j.n.Y G:i", strtotime($data->datum))'
),
array(
'name' => 'uporabnik_id',
'value' => 'Uporabnik::Model()->FindByPk($data->uporabnik_id)->upime',
'filter' => CHtml::listData(Uporabnik::model()->findAll(), 'id', 'upime'),
),
'naslov'
//specify the colums you wanted here
),
));
Problem 1:
In your model use
$criteria->compare('avtor.id', $this->uporabnik_id, true);
compare with id of relation avtor because that is what you have defined as value in dropdown in your gridview..CHtml::listData(Uporabnik::model()->findAll(), 'id', 'upime')..listData syntex is models, value, text..
Problem 2:
In your model use
$criteria->compare('t.id', $this->id);
t is the default alias used by the yii for the table...the problem with ambigious is that column id exists in both tables..
maybee in your db you have to set the foreign keys ; Cascade on Update and Cascade on Delete , if this dose not work than i would suspect the problem is with the relationship in the model that should have been generated correctly