Yii Get oldest object from db - findByAttributes - yii

Using a FindByAttributes query I would like to get the oldest element out of my database.
My Code:
$oMemberLocked = MembersLocked::model()->findByAttributes(array(
'lockedid' => $this->id,
'request' => 2,
));
The object MembersLocked has a attribute 'date'.
How can I get the element with the largest date?

You can order the query by ascending date.
$criteria = new CDbCriteria;
$criteria->order = 'date ASC';
$oMemberLocked = MembersLocked::model()->findByAttributes(array(
'lockedid' => $this->id,
'request' => 2,
), $criteria);

Related

how to convert query with multiple group by columns to CActiveDataProvider in Yii 1.1.14?

I need to conver this sql statement that has a multi column group by clause into CActiveDataProvider in Yii version 1.1.4?
select * from my_table_name group by bookname,categorytitle,bookkey order by bookname,categorytitle,bookkey asc;
I need a CActiveDataProvider to feed a CGridView search function. Apparently, I only have a simple return in my model of the search function that runs my CGridView
return new CActiveDataProvider(get_class($this),
array(
'criteria' => $criteria,
'sort' => array(
'defaultOrder' => 'id ASC'
),
'pagination' => array('pageSize' => ActiveRecord::PAGE_SIZE),
));
so how to convert the sql statement that I gave into CActiveDataProvider format ?
You can do using two way -
Make sql view and than create yii model and use this in your
controller or page view.
Create custom search function in your existing model and use group by
e.g. -
<?php
public function new_search(){
$criteria = new CDbCriteria();
...
..
$criteria->group = "bookname, categorytitle, bookkey";
$criteria->order = "bookname, categorytitle, bookkey";
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination'=>array('pageSize'=>100)
));
}
?>

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

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.

Displaying value from join table in Yii CgridView

I have this very simple table in my view and I'm trying to display value from joined table:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'skills-grid',
'dataProvider'=>$model->searchWithStudentSuccessRate($id),
'template' => '{items}{pager}',
'cssFile'=>Yii::app()->request->baseUrl. '/themes/'. Yii::app()->theme->name.'/css/table.css',
'htmlOptions'=>array('class'=>'datagrid', 'style'=>'width:550px;'),
'columns'=>array(
array(
'name'=>'name',
),
array(
'name' => 'value',
'header' => Yii::t('MainTrans', 'Value'),
'value' => '$data->student_skills->value',
),
array(
'name' => 'successRate',
'header' => Yii::t('MainTrans', 'Success Rate'),
'value' => '$data->successRate."%"',
),
),
));
And this is the search function:
public function searchWithStudentSuccessRate($id)
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('name',$this->name,true);
$criteria->compare('t.threshold',$this->threshold);
$criteria->with = array('student_skills');
$criteria->together = true;
$criteria->select = array('IFNULL(CASE WHEN ROUND((student_skills.value/t.threshold)*100,0) > 100 THEN 100 ELSE ROUND((student_skills.value/t.threshold)*100,0) END,0) as successRate','*');
$criteria->group = "t.name";
$criteria->condition = 'student_skills.student_id = '.$id;
$criteria->compare('successRate',$this->successRate);
$criteria->compare('student_skills.value',$this->value);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination'=>array(
'pageSize'=>25,
),
'sort'=>array(
'defaultOrder'=>array(
'successRate'=>CSort::SORT_DESC,
),
'attributes'=>array(
'successRate'=>array(
'asc'=>'successRate',
'desc'=>'successRate DESC',
),
'*',
),
),
));
}
But I get error: "Trying to get property of non-object" when I added value column to my CGridView.
Everything works fine without column value (columns successRate and name are fine). Relation should be fine as well. The error I get means that the value doesn't exist but it should since I did something similar in my other views and there it works.
Can anyone tell what's wrong? I'm sure it's something minor but I'm struggling with this embarrasing problem for a while.
Thanks
It means that in some conditions $data->student_skills is NULL. Try change this:
'value' => '$data->student_skills->value',
to this
'value' => 'empty($data->student_skills) ? null : $data->student_skills->value',

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,));