Altering table after generating CRUD code gives error in yii - yii

I have a table with 2 fields and generated CRUD which is working well. I added to 2 more fields to that table and applied required changes in model, controller and view. But yii shows error for the newly added fields saying that those attributes are not defined.
This is my model code:
class Product extends CActiveRecord
{
public function tableName()
{
return 'product';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, subTitle, image, shortDesc, longDesc, seo_title, focus_keywords, meta_desc, meta_url, created, updated', 'required'),
array('status', 'numerical', 'integerOnly'=>true),
array('title, subTitle, image', 'length', 'max'=>128),
array('seo_title, focus_keywords, meta_desc, meta_url', 'length', 'max'=>255),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, title, subTitle, image, shortDesc, longDesc, status, seo_title, focus_keywords, meta_desc, meta_url, created, updated', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'title' => 'Title',
'subTitle' => 'Sub Title',
'image' => 'Image',
'shortDesc' => 'Short Desc',
'longDesc' => 'Long Desc',
'status' => 'Status',
'seo_title' => 'Seo Title',
'focus_keywords' => 'Focus Keywords',
'meta_desc' => 'Meta Desc',
'meta_url' => 'Meta Url',
'created' => 'Created',
'updated' => 'Updated',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('title',$this->title,true);
$criteria->compare('subTitle',$this->subTitle,true);
$criteria->compare('image',$this->image,true);
$criteria->compare('shortDesc',$this->shortDesc,true);
$criteria->compare('longDesc',$this->longDesc,true);
$criteria->compare('status',$this->status);
$criteria->compare('seo_title',$this->seo_title,true);
$criteria->compare('focus_keywords',$this->focus_keywords,true);
$criteria->compare('meta_desc',$this->meta_desc,true);
$criteria->compare('meta_url',$this->meta_url,true);
$criteria->compare('created',$this->created,true);
$criteria->compare('updated',$this->updated,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Product the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}

Clear Yii cache (protected/runtime)

Related

What does CDBException mean here and how do I resolve it?

Please, I am totally new to Yii1.1, I am following a video tutorial and I have benn trying to follow up closely. I am trying to create and update the album model as indicated in the video tutorial. I typed everything the presenter typed: my codes are given below:
The AlbumController
class AlbumController extends Controller
{
/**
* #var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout='//layouts/column2';
/**
* #return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
'postOnly + delete', // we only allow deletion via POST request
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* #return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
'users'=>array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Displays a particular model.
* #param integer $id the ID of the model to be displayed
*/
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Album;
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if(isset($_POST['Album']))
{
$model->attributes=$_POST['Album'];
if($model->save()){
//$this->redirect(array('view','id'=>$model->id));
Yii::app()->user->setFlash('saved', 'Data saved!');
$this->redirect(array('update','id'=>$model->id));
}
else{
Yii::app()->user->setFlash('failure', 'Data not saved!');
}
}
$this->render('create',array(
'model'=>$model,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if(isset($_POST['Album']))
{
$model->attributes=$_POST['Album'];
if($model->save()){
//$this->redirect(array('view','id'=>$model->id));
Yii::app()->user->setFlash('saved', "Data saved!");
$this->redirect(array('update','id'=>$model->id));
}else{
Yii::app()->user->setFlash('failure', "Data not saved!");
}
}
$this->render('update',array(
'model'=>$model,
));
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* #param integer $id the ID of the model to be deleted
*/
}
public function actionDelete($id)
{
$this->loadModel($id)->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Album');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Album('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Album']))
$model->attributes=$_GET['Album'];
$this->render('admin',array(
'model'=>$model,
));
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
* #param integer $id the ID of the model to be loaded
* #return Album the loaded model
* #throws CHttpException
*/
public function loadModel($id)
{
$model=Album::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
/**
* Performs the AJAX validation.
* #param Album $model the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='album-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}
The Album model class
/**
* This is the model class for table "tbl_album".
*
* The followings are the available columns in table 'tbl_album':
* #property integer $id
* #property string $name
* #property string $tags
* #property integer $owner_id
* #property integer $shareable
* #property string $created_dt
*
* The followings are the available model relations:
* #property User $owner
* #property Photo[] $photos
*/
class Album extends CActiveRecord
{
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_album';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('owner_id, shareable, category_id', 'numerical', 'integerOnly'=>true),
array('name, tags', 'length', 'max'=>255),
array('description', 'length', 'max'=>1024),
array('description', 'match', 'pattern'=>'/[\w]+/u'),// \-\_\'\ \,\p{L}0-!
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, name, tags, owner_id, shareable, created_dt', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
//defined function beforeSave()..
protected function beforeSave(){
if(parent::beforeSave()){
if($this->isNewRecord){
$this->created_dt = new CDbExpression("NOW()");
$this->owner_id = Yii::app()->user->id;
}
return true;
}else
return false;
}
public function scopes(){
return array(
'shareable'=>array(
'order'=>'created_dt DESC',
'condition'=>'shareable=1',
)
);
}
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(
'owner' => array(self::BELONGS_TO, 'User', 'owner_id'),
'photos' => array(self::HAS_MANY, 'Photo', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'name' => 'Name',
'tags' => 'Tags',
'owner_id' => 'Owner',
'category_id'=>'Category',
'description'=>'Description',
'shareable' => 'Shareable',
'created_dt' => 'Created Dt',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('name',$this->name,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('description',$this->description);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Album the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
The Photo Model Class
/**
* This is the model class for table "tbl_photo".
*
* The followings are the available columns in table 'tbl_photo':
* #property integer $id
* #property integer $album_id
* #property string $filename
* #property string $caption
* #property string $alt_text
* #property string $tags
* #property integer $sort_order
* #property string $created_dt
* #property string $lastupdate_dt
*
* The followings are the available model relations:
* #property Comment[] $comments
* #property Album $album
*/
class Photo extends CActiveRecord
{
private $_uploads;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_photo';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('album_id, sort_order', 'numerical', 'integerOnly'=>true),
array('filename', 'length', 'max'=>500),
array('tags', 'length', 'max'=>256),
array('caption, alt_text, created_dt, lastupdate_dt', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, album_id, filename, caption, alt_text, tags, sort_order, created_dt, lastupdate_dt', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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', 'photo_id'),
'album' => array(self::BELONGS_TO, 'Album', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'album_id' => 'Album',
'filename' => 'Filename',
'caption' => 'Caption',
'alt_text' => 'Alt Text',
'tags' => 'Tags',
'sort_order' => 'Sort Order',
'created_dt' => 'Created Dt',
'lastupdate_dt' => 'Lastupdate Dt',
);
}
public function getImageParam(){
if(empty($this->_uploads)){
$this->_uploads = Yii::app()->params['uploads']. "/";
return $this->_uploads;
}
}
public function getUrl(){
return $this->getImageParam()."uploads/".CHtml::encode($this->filename);
}
public function getThumb(){
return $this->getImageParam()."thumbs/".CHtml::encode($this->filename);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('album_id',$this->album_id);
$criteria->compare('filename',$this->filename,true);
$criteria->compare('caption',$this->caption,true);
$criteria->compare('alt_text',$this->alt_text,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('sort_order',$this->sort_order);
$criteria->compare('created_dt',$this->created_dt,true);
$criteria->compare('lastupdate_dt',$this->lastupdate_dt,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Photo the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
The Photo Model
/**
* This is the model class for table "tbl_photo".
*
* The followings are the available columns in table 'tbl_photo':
* #property integer $id
* #property integer $album_id
* #property string $filename
* #property string $caption
* #property string $alt_text
* #property string $tags
* #property integer $sort_order
* #property string $created_dt
* #property string $lastupdate_dt
*
* The followings are the available model relations:
* #property Comment[] $comments
* #property Album $album
*/
class Photo extends CActiveRecord
{
private $_uploads;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_photo';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('album_id, sort_order', 'numerical', 'integerOnly'=>true),
array('filename', 'length', 'max'=>500),
array('tags', 'length', 'max'=>256),
array('caption, alt_text, created_dt, lastupdate_dt', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, album_id, filename, caption, alt_text, tags, sort_order, created_dt, lastupdate_dt', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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', 'photo_id'),
'album' => array(self::BELONGS_TO, 'Album', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'album_id' => 'Album',
'filename' => 'Filename',
'caption' => 'Caption',
'alt_text' => 'Alt Text',
'tags' => 'Tags',
'sort_order' => 'Sort Order',
'created_dt' => 'Created Dt',
'lastupdate_dt' => 'Lastupdate Dt',
);
}
public function getImageParam(){
if(empty($this->_uploads)){
$this->_uploads = Yii::app()->params['uploads']. "/";
return $this->_uploads;
}
}
public function getUrl(){
return $this->getImageParam()."uploads/".CHtml::encode($this->filename);
}
public function getThumb(){
return $this->getImageParam()."thumbs/".CHtml::encode($this->filename);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('album_id',$this->album_id);
$criteria->compare('filename',$this->filename,true);
$criteria->compare('caption',$this->caption,true);
$criteria->compare('alt_text',$this->alt_text,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('sort_order',$this->sort_order);
$criteria->compare('created_dt',$this->created_dt,true);
$criteria->compare('lastupdate_dt',$this->lastupdate_dt,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Photo the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
I am getting this error: CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (school2go2.tbl_album, CONSTRAINTtbl_album_ibfk_1FOREIGN KEY (owner_id) REFERENCEStbl_user(id) ON DELETE NO ACTION ON UPDATE NO ACTION). The SQL statement executed was: INSERT INTOtbl_album(name,tags,description,shareable,created_dt,owner_id) VALUES (:yp0, :yp1, :yp2, :yp3, NOW(), :yp4)
Please I am totally new to yii and even StackOverflow, pardon my inappropriate editing.I am still learning.
The error translates to: You are trying to insert an album without a corresponding owner.
Impossible to help more without knowing how you got that error.

yii how to select date range in queryall

Here is my query
$query= Yii::app()->db->createCommand()
->select('*,SUM(amount) AS TotalItemsOrdered')
->from('shoppinglist')
->where('user_type="Admin" ')
->group('cat_id,ing_id,measure_id')
->queryAll();
i have startdate from today and i add 6 days in current date to get last date ie complete week suppose
$startdate = "7-3-14"; //month-day-year
$enddate = "7-7-14";
how i use this code Date BETWEEN DATE('$DateFrom_order') AND DATE('$DateTo_order')
or i use in statement of mysql but how to use or ember on above YII query
EDIT
HERE IS MY MODEL
<?php
class Shoppinglist extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'shoppinglist';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('ing_id, measure_id, amount, user_id, cat_id, date_added, user_type', 'required'),
array('ing_id, measure_id, amount, user_id, cat_id', 'numerical', 'integerOnly'=>true),
array('user_type', 'length', 'max'=>5),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, ing_id, measure_id, amount, user_id, cat_id, date_added, user_type', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'ing_id' => 'Ing',
'measure_id' => 'Measure',
'amount' => 'Amount',
'user_id' => 'User',
'cat_id' => 'Cat',
'date_added' => 'Date Added',
'user_type' => 'User Type',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
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('ing_id',$this->ing_id);
$criteria->compare('measure_id',$this->measure_id);
$criteria->compare('amount',$this->amount);
$criteria->compare('user_id',$this->user_id);
$criteria->compare('cat_id',$this->cat_id);
$criteria->compare('date_added',$this->date_added,true);
$criteria->compare('user_type',$this->user_type,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
If the field Date in the database is DATE (type) then:
$query= Yii::app()->db->createCommand()
->select('*,SUM(amount) AS TotalItemsOrdered')
->from('shoppinglist')
->where("user_type='Admin' AND Date BETWEEN STR_TO_DATE( '$startdate', '%d-%m-%y' ) AND STR_TO_DATE( '$enddate', '%d-%m-%y' )")
->group('cat_id,ing_id,measure_id')
->queryAll();

Yii: change active record field names

I'm new to Yii and I have a table 'Student' with fields like 'stdStudentId', 'stdName', etc.
I'm making API, so this data should be returned in JSON. Now, because I want field names in JSON to just be like 'id', 'name', and I don't want all fields returned, i made a method in the model:
public function APIfindByPk($id){
$student = $this->findByPk($id);
return array(
'id'=>$student->stdStudentId,
'name'=>$student->stdName,
'school'=>$student->stdSchool
);
}
The problem is, stdSchool is a relation and in this situation, $student->stdSchool returns array with fields like schSchoolId, schName, etc. I don't want fields to be named like that in JSON, and also I don't want all the fields from School returned and I would like to add some fields of my own. Is there a way to do this in Yii, or I'll have to do it manually by writing methods like this?
I have been looking for the same thing. There is a great php lib named Fractal letting you achieve it: http://fractal.thephpleague.com/
To explain briefly the lib, for each of your models you create a Transformer that will be doing the mapping between your model attributes and the ones that need to be exposed using the api.
class BookTransformer extends Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
}
In the transformer you can also set the relation that this model have :
class BookTransformer extends TransformerAbstract
{
/**
* List of resources relations that can be used
*
* #var array
*/
protected $availableEmbeds = [
'author'
];
/**
* Turn this item object into a generic array
*
* #return array
*/
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
/**
* Here we are embeding the author of the book
* using it's own transformer
*/
public function embedAuthor(Book $book)
{
$author = $book->author;
return $this->item($author, new AuthorTransformer);
}
}
So at the end you will call
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Collection($books, new BookTransformer);
$json = $fractal->createData($resource)->toJson();
It's not easy to describe all the potential of fractal in one answer but you really should give it a try.
I'm using it along with Yii so if you have some question don't hesitate!
Since you are getting the values from the database using Yii active record, ask the database to use column aliases.
Normal SQL would be something like the following :
SELECT id AS Student_Number, name AS Student_Name, school AS School_Attending FROM student;
In Yii, you can apply Criteria to the findByPK() function. See here for reference : http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByPk-detail
$criteria = new CDbCriteria();
$criteria->select = 'id AS Student_Number';
$student = Student::model()->findByPk($id, $criteria);
Note that in order to use a column alias like that, you will have to define a virtual attribute Student_Number in your Student{} model.
Override the populateRecord() function of ActiveRecord can achieve this!
My DishType has 5 properties and override the populateRecord function Yii would invoke this when records fetched from db.
My code is here!
class DishType extends ActiveRecord
{
public $id;
public $name;
public $sort;
public $createTime;
public $updateTime;
public static function populateRecord($record, $row)
{
$pattern = ['id' => 'id', 'name' => 'name', 'sort' => 'sort', 'created_at' => 'createTime', 'updated_at' => 'updateTime'];
$columns = static::getTableSchema()->columns;
foreach ($row as $name => $value) {
$propertyName = $pattern[$name];
if (isset($pattern[$name]) && isset($columns[$name])) {
$record[$propertyName] = $columns[$name]->phpTypecast($value);
}
}
parent::populateRecord($record, $row);
}
}

CGridView Sorting with relational table sorts by relaton Id parameter

I have problem in CGrid while on sorting a relational data using relational model in `` page.
Briefly my scenario:
I have a user model: Entities=> id,username
And a profile Model: Entities=> id, firstname,lastname, user_id,etc..
I want to list profile model and username from user model in CGrid, so that sorting and searching perms well. In my case sorting username is done by user_id not by username. I want to search it by username,so i do the following,
My Controller Action:
$model = new Profile('search');
$model -> unsetAttributes();// clear any default values
if (isset($_GET['Profile']))
$model -> attributes = $_GET['Profile'];
$this -> render('MyPage', array('model' => $model ));
My Model Relation:
public function relations() {
// NOTE: you may need to adjust the relation name and the related
// class name the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'user', 'user_id'),);
}
Model Rules:
array( 'xxx,yyy,user_name', 'safe', 'on'=>'search' ),
And model search function
if(!empty($this->user_id)){
$criteria->with='user';
$criteria->order = ::app()->request->getParam('sort');// 'username ASC'
}
$criteria -> compare('user.username', $this->user_id, true);
My
$this->widget('zii.widgets.grid.CGrid', array(
'id'=>'profile-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
array('name'=>'user_id',
'header'=>User::model()->getAttributeLabel('username'),
'value' =>'$data->getRelated(\'user\')->username',
'type'=>'raw',
'htmlOptions'=>array('style'=>'text-align: center'),),
---------------
During sorting,sorting works perfectly but sorting is done on the basis of user_id not by username. Anything that i am missing to do so. Please suggest.
Reference:Here (I also tried as by declaring a public variable as suggesting in the link but bot workingg.)
Edit: After Issue Fixed.
Thanks for this link too.
Well, the wiki page you found is really a good start...
Here is an alternative way for doing this :
In your Profile model :
// private username attribute, will be used on search
private $_username;
public function rules()
{
return array(
// .....
array('username', 'safe', 'on'=>'search'),
// .....
);
}
public function getUsername()
{
// return private attribute on search
if ($this->scenario=='search')
return $this->_username;
// else return username
if (isset($this->user_id)) && is_object($this->user))
return $this->user->username;
}
public function setUsername($value)
{
// set private attribute for search
$this->_username = $value;
}
public function search()
{
// .....
$criteria->with = 'user';
$criteria->compare('user.username', $this->username, true);
// .....
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'username'=>array('asc'=>'user.username', 'desc'=>'user.username DESC'),
'*',
),
),
));
}
And in your view you should simply try :
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'profile-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
// .....
'username',
// .....
),
);

how to join 3 models to display data in a cgridview using yii

i am newbie in yii framework. I have 3 tables table A,table B,table C. table A and table B are related with primary and foreign key relationship.same way table B and table C are linked with priamary and foreign key relationshiop..i want to display,filter data in cgridview of admin page..using a yii fra
updated:
i have 3 models.subscriber.php,assignment.php,groups.php
i want to display attributes from 3 models and display them in cgridview of subscriber.php???
subscriber.php..........
/**
* This is the model class for table "users_phone_numbers".
*
* The followings are the available columns in table 'users_phone_numbers':
* #property integer $id
* #property string $name
* #property string $phone_number
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
* #property integer $status
* #property string $message_type
* #property string $birthdate
* #property string $email
*
* The followings are the available model relations:
* #property PhoneNumberGroupAssignment[] $phoneNumberGroupAssignments
*/
class subscriber extends CActiveRecord
{
//public $group_search; //for searching and displaying in cgridview
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return subscriber the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'users_phone_numbers';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('phone_number, created_user, created_date, birthdate, email', 'required'),
array('created_user, modified_user, status', 'numerical', 'integerOnly'=>true),
array('name, phone_number', 'length', 'max'=>100),
array('message_type', 'length', 'max'=>20),
array('email', 'length', 'max'=>150),
array('modified_date', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, name, phone_number, created_user, created_date, modified_user, modified_date, status, message_type, birthdate, email ', 'safe', 'on'=>'search'),//add above defined variable.
);
}
/**
* #return array relational rules.
*/
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(
'phoneNumberGroupAssignments' => array(self::HAS_MANY, 'Assignment', 'phone_number_id'),
//'postCount' => array(self::STAT, 'assignment', 'phone_number_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'name' => 'Name',
'phone_number' => 'Phone Number',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
'status' => 'Status',
'message_type' => 'Message Type',
'birthdate' => 'Birthdate',
'email' => 'Email',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
//$criteria->with = array( 'phoneNumberGroupAssignments' ); //new
$criteria->compare('id',$this->id);
$criteria->compare('name',$this->name,true);
$criteria->compare('phone_number',$this->phone_number,true);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
$criteria->compare('status',$this->status);
$criteria->compare('message_type',$this->message_type,true);
$criteria->compare('birthdate',$this->birthdate,true);
$criteria->compare('email',$this->email,true);
//$criteria->compare( 'phoneNumberGroupAssignments.group_id', $this->group_search, true );
return new CActiveDataProvider($this, array('criteria'=>$criteria,
/*'sort'=>array(
'attributes'=>array(
'group_search'=>array(
'asc'=>'phoneNumberGroupAssignments.group_id',
'desc'=>'phoneNumberGroupAssignments.group_id DESC',
),
),
),
*/
));
}
}
2nd assignment.php
/**
* This is the model class for table "phone_number_group_assignment".
*
* The followings are the available columns in table 'phone_number_group_assignment':
* #property integer $id
* #property integer $phone_number_id
* #property integer $group_id
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
*
* The followings are the available model relations:
* #property UsersPhoneNumbers $phoneNumber
*/
class assignment extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return assignment the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'phone_number_group_assignment';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('phone_number_id, group_id, created_date', 'required'),
array('phone_number_id, group_id, created_user, modified_user', 'numerical', 'integerOnly'=>true),
array('modified_date', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, phone_number_id, group_id, created_user, created_date, modified_user, modified_date', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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(
'phoneNumber' => array(self::BELONGS_TO, 'Subscriber', 'phone_number_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'phone_number_id' => 'Phone Number',
'group_id' => 'Group',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
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('phone_number_id',$this->phone_number_id);
$criteria->compare('group_id',$this->group_id);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
3rd one :
groups.php
/**
* This is the model class for table "client_groups".
*
* The followings are the available columns in table 'client_groups':
* #property integer $id
* #property integer $client_id
* #property string $title
* #property string $keywords
* #property integer $status
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
* #property integer $is_default
* #property integer $is_special_group
* #property string $back_office_no
* #property string $special_group_sms_text
* #property string $text_sms_office
* #property string $day_delay_1
* #property string $subscription_sms_1
* #property string $day_delay_2
* #property string $subscription_sms_2
* #property string $day_delay_3
* #property string $subscription_sms_3
* #property string $campaign_sms
* #property string $delay_time_1
* #property string $delay_time_2
* #property string $delay_time_3
* #property integer $msg_counter
* #property integer $msg_counter_start_num
* #property integer $add_expiry
* #property integer $add_days
* #property integer $phone_number_id
* #property integer $ar_type
* #property string $email
*
* The followings are the available model relations:
* #property ClientInformation $client
*/
class Groups extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Groups the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'client_groups';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('client_id, created_user, created_date, msg_counter, add_expiry, add_days, phone_number_id, ar_type, email', 'required'),
array('client_id, status, created_user, modified_user, is_default, is_special_group, msg_counter, msg_counter_start_num, add_expiry, add_days, phone_number_id, ar_type', 'numerical', 'integerOnly'=>true),
array('title', 'length', 'max'=>250),
array('keywords', 'length', 'max'=>255),
array('back_office_no', 'length', 'max'=>50),
array('day_delay_1, day_delay_2, day_delay_3', 'length', 'max'=>3),
array('subscription_sms_1, subscription_sms_2, subscription_sms_3, campaign_sms, email', 'length', 'max'=>200),
array('modified_date, special_group_sms_text, text_sms_office, delay_time_1, delay_time_2, delay_time_3', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, client_id, title, keywords, status, created_user, created_date, modified_user, modified_date, is_default, is_special_group, back_office_no, special_group_sms_text, text_sms_office, day_delay_1, subscription_sms_1, day_delay_2, subscription_sms_2, day_delay_3, subscription_sms_3, campaign_sms, delay_time_1, delay_time_2, delay_time_3, msg_counter, msg_counter_start_num, add_expiry, add_days, phone_number_id, ar_type, email', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
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(
'client' => array(self::BELONGS_TO, 'ClientInformation', 'client_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'client_id' => 'Client',
'title' => 'Title',
'keywords' => 'Keywords',
'status' => 'Status',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
'is_default' => 'Is Default',
'is_special_group' => 'Is Special Group',
'back_office_no' => 'Back Office No',
'special_group_sms_text' => 'Special Group Sms Text',
'text_sms_office' => 'Text Sms Office',
'day_delay_1' => 'Day Delay 1',
'subscription_sms_1' => 'Subscription Sms 1',
'day_delay_2' => 'Day Delay 2',
'subscription_sms_2' => 'Subscription Sms 2',
'day_delay_3' => 'Day Delay 3',
'subscription_sms_3' => 'Subscription Sms 3',
'campaign_sms' => 'Campaign Sms',
'delay_time_1' => 'Delay Time 1',
'delay_time_2' => 'Delay Time 2',
'delay_time_3' => 'Delay Time 3',
'msg_counter' => 'Msg Counter',
'msg_counter_start_num' => 'Msg Counter Start Num',
'add_expiry' => 'Add Expiry',
'add_days' => 'Add Days',
'phone_number_id' => 'Phone Number',
'ar_type' => 'Ar Type',
'email' => 'Email',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
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('client_id',$this->client_id);
$criteria->compare('title',$this->title,true);
$criteria->compare('keywords',$this->keywords,true);
$criteria->compare('status',$this->status);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
$criteria->compare('is_default',$this->is_default);
$criteria->compare('is_special_group',$this->is_special_group);
$criteria->compare('back_office_no',$this->back_office_no,true);
$criteria->compare('special_group_sms_text',$this->special_group_sms_text,true);
$criteria->compare('text_sms_office',$this->text_sms_office,true);
$criteria->compare('day_delay_1',$this->day_delay_1,true);
$criteria->compare('subscription_sms_1',$this->subscription_sms_1,true);
$criteria->compare('day_delay_2',$this->day_delay_2,true);
$criteria->compare('subscription_sms_2',$this->subscription_sms_2,true);
$criteria->compare('day_delay_3',$this->day_delay_3,true);
$criteria->compare('subscription_sms_3',$this->subscription_sms_3,true);
$criteria->compare('campaign_sms',$this->campaign_sms,true);
$criteria->compare('delay_time_1',$this->delay_time_1,true);
$criteria->compare('delay_time_2',$this->delay_time_2,true);
$criteria->compare('delay_time_3',$this->delay_time_3,true);
$criteria->compare('msg_counter',$this->msg_counter);
$criteria->compare('msg_counter_start_num',$this->msg_counter_start_num);
$criteria->compare('add_expiry',$this->add_expiry);
$criteria->compare('add_days',$this->add_days);
$criteria->compare('phone_number_id',$this->phone_number_id);
$criteria->compare('ar_type',$this->ar_type);
$criteria->compare('email',$this->email,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
current cgrid view is accessing data from two models,assignemnt and subscriber but not from groups. and it givers error rying to get property of non-object
C:\wamp\www\yii\framework\base\CComponent.php(607) : eval()'d code(1)
..so plz check this for 2 and then for 3 models? urgent help needed.thanks
From the admin view for table A you should be able to access the other values by listing them like this in the column definition:
'columns'=>array(
array('name'=>'column heading 1','value'=>'$data->modelB_nameinA->col_name1'),
array('name'=>'column heading 2','value'=>'$data->modelB_nameinA->C->col_name2'),
For filtering on these values you need to be able to access them in the modelA->search() function. The simplest way I have found to do that is to explicitly set a public value in A for each col_name you want to display from B and C. You need to also include them in the safe search statement in modelA->rules() and for simplicity also in the modelA->attributeLabels(). You might also have to include C in the relations of A, so the modelA class would look something like this:
class A extends CActiveRecord
{
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
...
// Please remove those attributes that should not be searched.
array('Col1_fromA, Col2_fromA, Col1_fromB, Col1_fromC', 'safe', 'on'=>'search'),
);
}
/**
* Put here the names of the columns from B and C that you are wanting to filter on
*/
public $Col1_fromB;
public $Col1_fromC;
/**
* #return array relational rules.
*/
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(
'modelB_nameinA' => array(self::HAS_MANY, 'B', 'B_id'),
'modelC_nameinA' => array(self::HAS_MANY, 'C', array('C_id'=>'id'),'through'=>'B'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'Col1_fromA' => 'Fancy name for Col1_fromA',
'Col2_fromA' => 'Fancy name for Col2_fromA',
'Col1_fromB' => 'Fancy name for Col1_fromB',
'Col1_fromC' => 'Fancy name for Col1_fromC',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
// this is so those two tables are included in the SQL generated:
$criteria->with = array( 'B', 'C' );
$criteria->together=true;
$criteria->compare('Col1_fromA',$this->Col1_fromA,true);
$criteria->compare('Col2_fromA',$this->Col2_fromA,true);
$criteria->compare('modelB_nameinA.Col1', $this->Col1_fromB,true);
$criteria->compare('modelC_nameinA.Col1', $this->Col1_fromC,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
...
One advantage of this is that you can now use the Col1_fromB and Col1_fromC as the name value in the columns definition in cgridview and you will get the fancy names you entered in the definition of modelA as column headings.
You need to define relations in table A and B to get model C from table A.
Table A relations:
public function relations() {
return array(
'tableB'=>array(self::HAS_ONE, 'TableB', 'tablea_id'),
);
}
Table B relations:
public function relations() {
return array(
'tableC'=>array(self::HAS_ONE, 'TableC', 'tableb_id'),
);
}
So you can acces tableB and tableC model, related with your tableA:
$modelB = $tableA->tableB;
$modelC = $tableA->tableB->tableC;
You can read here about relational active record.
In your controller action get the model:
public function actionGrid() {
$model = new ModelA('search');
$model->unsetAttributes();
$this->render('view', array('model'=>$model));
}
And view code with CGridView:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'grid',
'dataProvider'=>$model->search(),
'filter' => $model,
'ajaxUpdate'=>false,
'selectableRows'=>'10',
'columns'=>array(
array(
'id'=>'checkBoxId',
'class'=>'CCheckBoxColumn',
),
array(
'class'=>'CDataColumn',
'name'=>'modelA_attrib1',
'value'=>'$data->attrib1',
'sortable'=>true,
'filter'=>true,
),
array(
'class'=>'CDataColumn',
'name'=>'modelB_attrib1',
'value'=>'$data->modelB->attrib1',
'sortable'=>true,
'filter'=>true,
),
array(
'class'=>'CDataColumn',
'name'=>'modelC_attrib1',
'value'=>'$data->modelB->modelC->attrib1',
'sortable'=>true,
'filter'=>true,
),
...
Update:
If I properly understood, you have MANY_TO_MANY relation within your users_phone_numbers and client_groups tables (group could be related with many phone numbers, and number refer to many groups).
So phone_number_group_assignment (commonly referred to as phone_number_group) must contain two primary keys:
* #property integer $phone_number_id
* #property integer $group_id
And relations of subscriber:
public function relations()
{
return array(
'groups' => array(self::MANY_MANY, 'Groups', 'phone_number_group_assignment(phone_number_id, group_id)'),
);
}
Relations for groups:
public function relations()
{
return array(
'phone_numbers' => array(self::MANY_MANY, 'Subscriber', 'phone_number_group_assignment(group_id, phone_number_id)'),
);
}
So you can access groups from subscriber: $subscriber->groups
make a view in database and put all your needed columns after joins operations and then make the model.
I use this always
As #user181452 said, create a View and then generate a model. Other way would be that in your target model, bind each new attribute with a public variable in the model
class NewModel {
public $new_attribute;
}
Then you would be able to access to it from views. You have to chose the cleanest way for your project, 'cause create a view is better if you have a complex JOIN.