I am trying to set up a MANY_MANY Relationship in Yii using Active Record.
I have three tables
profile
profile_id
profile_description
category
category_id
category_name
profile_category
profile_id
category_id
My models are Profile, Category, and ProfileCategory.
I am trying to run a query using the category_id that will pull up all of the profiles that are in that category.
This is the information in the category model.
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(
'profiles'=>array(
self::MANY_MANY,
'Profile',
'profile_category(category_id, profile_id)',
),
'profile_category'=>array(
self::HAS_MANY,
'ProfileCategory',
'category_id',
),
);
}
Profile Model
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(
'categories'=>array(
self::MANY_MANY,
'Category',
'profile_category(profile_id, category_id)'
),
'profileCategory'=>array(
self::HAS_MANY,
'ProfileCategory',
'profile_id'
),
);
}
ProfileCategory Model
public function relations()
{
return array(
'category'=>array(
self::BELONGS_TO,
'Category',
'category_id',
),
'profile'=>array(
self::BELONGS_TO,
'Profile',
'profile_id',
),
);
}
Controller
public function actionResults()
{
$category=$_POST['terms'];
$dataProvider=new CActiveDataProvider(
'Profile',
array(
'criteria'=>array(
'with'=>array('profile_category'),
'condition'=>'display=10 AND profile_category.category_id=1',
'order'=>'t.id DESC',
'together'=>true,
),
)
);
$this->render('results',array(
'dataProvider'=>$dataProvider,
));
}
View
<div id=resultsleft>
<?php
foreach($dataProvider as $value)
{
echo $value->profile_id;
}
?>
</div>
Any thoughts? Thank You! Nothing shows in the view.
You have to set up a property called profileCategory (not profile_category) in the profile model:
'profileCategory'=>array(
self::HAS_MANY,
'ProfileCategory',
'profile_id'
),
You can use it with an and condition as follows:
'criteria'=>array(
'with'=>array('profileCategory'),
'condition'=>'display=10 AND profileCategory.category_id=1',
'order'=>'t.id DESC',
'together'=>true,
),
It would be better for logical id first to model relation...
An example is available here.
Category model
'Profile', 'profile_category(profile_id, ...)'
public function relations()
{
return array(
'profiles'=>array(
self::MANY_MANY,
'Profile',
'profile_category(profile_id, category_id)'
),
'profile_category'=>array(
self::HAS_MANY,
'ProfileCategory',
'category_id',
),
);
}
Profile model
'Category', 'profile_category(category_id, ...)'
public function relations()
{
return array(
'categories'=>array(
self::MANY_MANY,
'Category',
'profile_category(category_id, profile_id)'
),
'profile_category'=>array(
self::HAS_MANY,
'ProfileCategory',
'profile_id'
),
);
}
Its actualy if model of database has
many self::BELONGS_TO and database has only PK (PrimaryKeys)
such code will be correctly executed
print_r(Profile::model()->findByPk(5)->categories);
print_r(Category::model()->findByPk(8)->profiles);
Related
I have a HAS_MANY relation between 2 models, i use bookID as foreign key
model 1 - Importedbooks, Importedbooks can have many CountryOfImport
public function relations()
{
return array(
'CountryOfImportObj'=>array(self::HAS_MANY, 'CountryOfImport', 'bookID')
);
}
model 2 CountryOfImport, CountryOfImport belongs to Importedbooks
public function relations()
{
return array(
'ImportBooksObj'=>array(self::BELONGS_TO, 'Importedbooks', 'bookID')
);
}
Now, For my CGridView i am using a model->search()of the Importedbooks model as my dataProvider, From here is where i get stuck.
CGridView
$data = $model->search();
$data->setPagination(array('pageSize'=>'5'));
$data->criteria->addCondition('active = "yes"');
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$data
,'filter'=>$model
,'pager'=>array('header'=>'')
,'columns'=>array(
'id',
'bookYear',
'bookTitle',
'DISPLAY VALUE FROM OTHER model HERE'
)
)
);
DataProvider of the Imported books model, i'm using this as my data provider for the grid
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('bookID',$this->bookID);
$criteria->compare('countryName',$this->countryName,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
The relation works because i can use below code in my controller to get a field(countryName) from the other model
$model = Importedbooks::model()->with('CountryOfImportObj')->findbyPK(3);
print_r($model->CountryOfImportObj[0]->countryName);
Such as Importedbooks have many CountryOfImport, in one row you must show or all country names or concreet names depending on ID or countryName or some other attribute.
You can pass anonymous function as value:
'columns' => array(
'id',
'bookYear',
'bookTitle',
array(
'header' => 'Countries',
'type' => 'raw',
// if you have defined counrtyName attribute in 'Importedbooks' model, if not you can remove this row
// also CGridView 'uses' attribute 'name' for filtering or sorting
'name' => 'countryName',
'value' => function($data, $row) { //$data is item of DataProvider, $row is number of row (starts from 0)
$countries = CHtml::listData((array)$data->CountryOfImportObj, 'id', 'countryName');
return implode(', ', $countries);
}
)
)
If you want to filter or sort by external attributes too, you must "declare them"
Thanks!
Yii 1.1.14
I have an employee table and a comment table
In the employee view i want to show all the comments of the employee in a grid (after the employee fields)
I tried to follow the example here
Here is where I am :
New code to defining a new search function in the model :
public $commentdate_param;
public $commentobservation_param;
...
public function rules()
{
return array(
...
array('public $commentdate_param, commentobservation_param, ...', 'safe', 'on'=>'search, searchIncludingComments'),
);
public function relations()
{
return array(
...
'employeecomments' => array(self::HAS_MANY, 'Employeecomments', 'employee_id'),
);
}
public function searchIncludingComments($parentID)
{
$criteria=new CDbCriteria;
$criteria->with=array('employeecomments');
$criteria->together = true;
$criteria->compare('t.employee_id',$parentID,false);
$criteria->compare('employeecomments.date', $this->commentdate_param,true);
$criteria->compare('employeecomments.observation', $this->commentobservation_param,true);
$sort = new CSort;
$sort->attributes = array(
'commentdate_param' => array(
'asc' => 'date_desc',
'desc' => 'date_desc DESC',
), '*', /* Treat all other columns normally */
);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>$sort,
));
}
Adding code in the controller actionView :
...
$child_model = new Employee("searchIncludingComments");
$child_model->unsetAttributes();
$this->render('view',array(
'model'=>$this->loadModel($id),
'child_model'=>$child_model,
'parentID' => $id
));
Adding code in the view :
...
<h3>Comments</h3>
<?php
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'child-grid',
'dataProvider'=>$child_model->searchIncludingComments($parentID),
'filter'=>$child_model,
'columns'=>array(
'date',
'observation',
array(
'class'=>'CButtonColumn',
),
),
));
...
But I must have missed something because when it comes to grid rendering stops - but no error in log
Would be nice if somebody could help me !
I found the solution for me - all my changes and controler are worthless because now I do all stuff in the view :
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'comments-grid',
'dataProvider'=>new CActiveDataProvider('Employeecomment',array(
'criteria'=>array(
'condition'=>'employee_id=:eid',
'params'=>array(':eid'=>$model->id),
),
'sort'=>array(
'defaultOrder'=>'date DESC',
),
)),
Sure there is something I did not understand why it did not work ...
I have 2 tables/models:
Tmp1
Header
QuestionText
Tmp2
Header
Part
OutOf
I'm trying to display the columns: Header, QuestionText, Part, OutOf
in a single CGRIDVIEW.
In Tmp1 model:
public function relations()
{
return array(
'tmp2s' => array(self::HAS_MANY, 'Tmp2', 'Header'),
);
}
In Tmp2 Model:
public function relations()
{
return array(
'header' => array(self::BELONGS_TO, 'Tmp1', 'Header'),
);
}
Controller:
public function actionReviewAll()
{
$tmp1 = new Tmp1('search');
$tmp1->unsetAttributes();
if(isset($_GET['Tmp1'])){
$model->attributes=$_GET['Tmp1'];
}
$this->render('ReviewAll',array(
'tmp1'=>$tmp1,
));
}
View:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'tmp-grid',
'dataProvider'=>$tmp1->search(),
'filter'=>$tmp1,
'columns'=>array(
'Header',
'QuestionText',
array(
'name' => 'tmp2.OutOf',
'value' => '$data->tmp2[0].OutOf',
'type' => 'raw'
),
),
)); ?>
Error:
Property "Tmp1.tmp2" is not defined.
Any help is greatly appreciated
You have a sintax error:
Tmp1.tmp2 = Tmp1.tmp2s
The relation alias is with 's'. "tmp2s".
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'tmp-grid',
'dataProvider'=>$tmp1->search(),
'filter'=>$tmp1,
'columns'=>array(
'Header',
'QuestionText',
'tmp2s.Part',
'tmp2s.OutOf',
),
)); ?>
But you are trying to show a 'self::HAS_MANY' relationship, you can't show that on a normal CGridView widget...
Your code probably works (I haven't tried it), but not in cases where your tmp1 model has no tmp2's. You must make sure there is a tmp2 before accessing it:
'value' => 'isset($data->tmp2) ? $data->tmp2[0].OutOf : Null',
You can also pass a function($data,$row) to value to make it look less messy. (Yes, that's important to me.)
i am trying to display two database tables source in one CGridView..
2 tables were reg.students and login.user..
my students model relation is,
public function relations()
{
Yii::app()->getModule('user');
return array(
'royaltyOutstandings' => array(self::HAS_MANY, 'RoyaltyOutstanding', 'studentID'),
'srkMedicalInfos' => array(self::HAS_MANY, 'SrkMedicalInfo', 'studentID'),
'parents' => array(self::HAS_ONE, 'SrkParents', 'studentID'),
'srkStudentWorksheets' => array(self::HAS_MANY, 'SrkStudentWorksheet', 'studentID'),
'user' => array(self::BELONGS_TO, 'User', 'centre_id'),
);
}
In user module,
public function tableName()
{ return 'login.user'; }
in cgridview columns array,
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'students-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'header' => 'No.',
'value' => '$row+1',
),
array('name' => 'user.centre_id',
'value'=>'$data->user->centre_id',
),
'... // & so on
Controller action is,
public function actionAdmin()
{
$this->layout = 'column3';
$form = new Reports ;
$model=new Students('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Students']))
$model->attributes=$_GET['Students'];
$this->render('admin',array(
'model'=>$model,
'form'=>$form,
));
}
If I understand you correctly, you want to show one or more relations in your gridview.
If this is what you want, have a look at this tutorial: http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview/
This tutorial doesn't only show you how to show a relation in your gridview but it also shows you how to sort and filter the data. good luck!
I have a strange problem with my yii application. I have two tables in my database Players - id, name, team_id and Teams - id, name. I can create new players but when I want to see player's profile there is an error -"Trying to get property of non-object" at this line:
'value'=>$model->team->NAME,
The most strange problem is that when I test url for players with Ids 1 and 2 everything is okay and I see the correct information, but for other ids I have this problem. Here is part of my code:
view.php
<?php $this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>array(
'ID',
'NAME',
'TEAM_ID',
array(
'label'=>'Отбор',
'type'=>'text',
'value'=>$model->team->NAME,
),
),
)); ?>
Players.php
public function relations()
return array(
'team' => array(self::BELONGS_TO, 'TEAMS', 'ID'),
);
}
Teams.php
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(
'player' => array(self::HAS_MANY, 'PLAYERS', 'ID'),
);
}
PlayersController.php
public function actionView($id)
{
$teams = new CActiveDataProvider('Teams');
$players = new CActiveDataProvider('Players');
$this->render('view', array(
'model'=>$this->loadModel($id),
));
}
Seems like you need to fix bug with relations in Players model:
public function relations()
return array(
'team' => array(self::BELONGS_TO, 'TEAMS', 'TEAM_ID'), // TEAM_ID instead of ID
);
}