Search with a joined table using YII - php

I have the following table structure.
tb_posts has the field author_id which relates to tb_author.id
in YII i have the following in my posts activeRecord
public function relations()
{
return array(
'authorRelation' => array(self::BELONGS_TO, 'authorRecord', 'author')
);
}
How i do a search of posts of an authors with name 'foo'? I am trying the following with no success
$criteria=new CDbCriteria;
$criteria->with = array('authorRelation');
$criteria->together = true;
$criteria->compare( 'author.name', 'foo', true );
$posts=PostsRecord::model()->findAll($criteria);

Set table alias for your models at init.
class PostsRecord extends CActiveRecord
{
// ...
public function init() { $this->setTableAlias( 'postsrecord' ); }
// ...
}
class AuthorRecord extends CActiveRecord
{
// ...
public function init() { $this->setTableAlias( 'authorrecord' ); }
// ...
}
Finally:
$condition=new CDbCriteria;
$condition->with = array('authorRelation');
$condition->together = true;
$condition->condition = 'authorrecord.name=:authorname';
$condition->params = array( ':authorname' => 'foo' );
$posts=PostsRecord::model()->findAll($condition);

Your relation should be 'authorRelation' => array(self::BELONGS_TO, 'authorRecord', author_id'). The 3rd parameter is the foreign key.
The second part of the code doesn't have any errors, the search should work if you set up the relations correctly.

Related

Yii, relation model filter search

I am battling with CGridView filtering using the related model column, I have two models Cars and Colour, so Colour has_many Car and Car belongs_to Colour. The grid column from related model displays fine, I'm just not able to filter with it. I am getting mysql error
Column not found: 1054 Unknown column 'carName'
Colour model HAS_MANY - Cars
I declaired the variable $carName from the Car model, so this model can see it.
public $carName;
public function rules()
{
return array(
array('id, carName, colourName', 'safe', 'on'=>'search'),
)
}
public function relations()
{
return array(
'CarsObj'=>array(self::HAS_MANY, 'Cars', 'colourID')
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->with = "CarsObj";
$criteria->compare('carName', $this->carName, true);
$criteria->compare('id',$this->id);
$criteria->compare('colourName',$this->colourName,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Car Model BELONGS_TO - Colour
public function relations()
{
return array(
'ColourObj'=>array(self::BELONGS_TO, 'Colour', 'colourID')
);
}
CGridView, i am using the Colour Model search as my dataProvider
$model = new Colour('search');
$data = $model->search();
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$data
,'filter'=>$model
,'pager'=>array('header'=>'')
,'columns'=>array( //related model column
'id',
'colourName',
array(
'header' => 'carName',
'type' => 'raw',
'name' => 'carName',
'value' => function($data, $row) { //$data is item of DataProvider, $row is number of row (starts from 0)
$carNames= CHtml::listData((array)$data->ColourObj, 'id', 'carName');
return implode(', ', $carNames);
}
)
By default CActiveRecord using lazy load. You need to set attribute together true. Also it's a good practice to set table alias when you using with.
public function search(){
$criteria=new CDbCriteria;
$criteria->together = true;
$criteria->with = 'CarsObj';
$criteria->compare('CarsObj.carName',$this->carName,true);
$criteria->compare('t.id',$this->id);
$criteria->compare('t.colourName',$this->colourName,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Try this
public function search()
{
$criteria=new CDbCriteria;
$criteria->with = "CarsObj";
$criteria->compare('CarsObj.carName', $this->carName, true);
$criteria->compare('id',$this->id);
$criteria->compare('colourName',$this->colourName,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}

How to get data of 2nd table yii find all criteria join

This is companycontent model relations:
public function relations() {
return array(
'company_content_lang' => array(self::HAS_MANY, 'CompanyContentLang', 'company_content_id'),
);
}
This is my query:
$criteria = new CDbCriteria();
$criteria->select='t.tab_content, mv.label AS label, t.is_active';
$criteria ->join='INNER JOIN master_value as mv
on mv.value = t.tab_type
AND value_code = "tab_content"
AND locale = "' . Yii::app()->language . '"';
$criteria ->condition = 'company_id = :company_id AND is_deleted =0';
$criteria ->params=array(':company_id' => (int) $id);
$criteria->order='mv.order';
$modelContent = CompanyContent::model()->findAll($criteria);
Relationship between company_content and master_value is company_content.tab_type = master_value.value AND master_value.value_code='tab_content'. So I can't make this relation in company_content model.
Please show me how to get "mv.label AS label" value.
First, show us the relations() at CompanyContent model.
Usually, it's just a simple thing. Just add public property/variable inside the CompanyContent, ex:
class CompanyContent extends CActiveRecord
{
public $label; //added
...

Yii framework: get sum by scope

I have scopes in my User model:
public function scopes()
{
return array(
'sumPrice'=>array(
'select'=>'SUM(`price`)',
),
);
}
And I want get sumPrice in controller, but I dont know what is a way to do this. I tried:
$sumPrice=User::model()->sumPrice(); //it returns empty record (user model filled by NULLs)
$sumPrice=User::model()->sumPrice()->count(); //it returns count records in user
$sumPrice=User::model()->sumPrice()->findAll(); //it returns all records in user
But there isn't function which return sum, so how to get it?
Solved:
$sumPrice = Yii::app()->db->createCommand('SELECT SUM(`price`) AS `sum` FROM `user`')->queryAll();
var_dump($sumPrice[0]['sum']);
You need a Statistical query on your active record, define a relation on your model
class Post extends CActiveRecord
{
public function relations()
{
return array(
'commentCount'=>array(self::STAT, 'Comment', 'post_id'),
'categoryCount'=>array(
self::STAT, 'Category', 'post_category(post_id, category_id)'
),
);
}
}
Yiiframework
you can use ActiveRecord :
$criteria = new CDbCriteria;
$criteria->select='SUM(your_column) as sum';
$criteria->condition='your_condition';
$user = User::model()->find($criteria);
and you need to declare: public $sum; in your model class. (Using the above example.)

yii relation for multiple column foreign keys

I have a table Friend (PersonA, PersonB). These are foreign keys of Person(id, name).
I want to create a Yii relation between them. This is what I have come up with:
public function relations() {
return array(
'friends1' => array(self::HAS_MANY, 'Friend', 'PersonA'),
'friends2' => array(self::HAS_MANY, 'Friend', 'PersonB'),
);
}
Is there a way to combine these two relations into one? I was hoping for something like this:
public function relations() {
return array(
'allFriends' => array(self::HAS_MANY, 'Friend', 'PersonA, PersonB'),
);
}
Any ideas?
EDIT #1:
For completeness, let's also imagine that I want to order friends1 and friends2 like this:
public function relations() {
return array(
'friends1' => array(self::HAS_MANY, 'Friend', 'PersonA', 'order'=>'id ASC'),
'friends2' => array(self::HAS_MANY, 'Friend', 'PersonB', 'order'=>'id ASC'),
);
}
This solution worked for me :
Override the __get function in your model:
public function __get($name)
{
if(($name == 'friends1') || ($name == 'friends2')) {
return parent::__get('friends1') + parent::__get('friends2');
}
else
return parent::__get($name);
}
I had the exact same thing come up in something I was working on. What I did is I created another function to compile the two relations into one array. The reason for this is because even if you were to get the two relationships combined, each time you would still need to test to see if PersonA or PersonB is the current user's id and use the other id to pull the Friends info. Here is the function I created in my model:
public function getFriends() {
$all_friends = array();
foreach($this->friends1 as $friend) {
if($friend->PersonA == $this->id) {
$all_friends[] = $friend->PersonA;
} else {
$all_friends[] = $friend->PersonB;
}
}
foreach($this->friends2 as $friend) {
if($friend->PersonA != $this->id) {
$all_friends[] = $friend->PersonA;
} else {
$all_friends[] = $friend->PersonB;
}
}
return $all_friends;
}
Another options:
public function getFriends() {
$criteria = new CDbCriteria;
$criteria->compare('PersonA',$this->id);
$criteria2 = new CDbCriteria;
$criteria2->compare('PersonB',$this->id);
$criteria->mergeWith($criteria2,'OR');
$friends = Challenge::model()->findAll($criteria);
return $friends;
}
Then for any Person you can just say:
$person = Person::model()->findByPk(1);
$friends = $person->friends;
Or instead of an array you could send back an CActiveDataProvider that you could do sorts and other things with. You could do this:
public function getFriends() {
$criteria = new CDbCriteria;
$criteria->compare('PersonA',$this->id);
$criteria2 = new CDbCriteria;
$criteria2->compare('PersonB',$this->id);
$criteria->mergeWith($criteria2,'OR');
return new CActiveDataProvider('Friend', array(
'criteria' => $criteria,
));
}
Then since you have CActiveDataProvider you can sort:
$friends = $user->friends->getData(); //not sorted or anything
//or you can manipulate the CActiveDataprovider
$data = $user->friends;
$data->setSort(array(
'defaultOrder'=>'PersonA ASC',
));
$friends = $data->getData();

Yii - how to retrieve model data into a layout page?

I wish to list some Categories name on my layout main.php page.
Since the layout doesn't have any associated controller or model, I wish to create a static method like this on Category model:
public static function getHeaderModels()
{
// get all models here
return $models;
}
and then in the main layout
<?php
$models = Category::getHeaderModels();
foreach($models as $model)
{
// ....
}
?>
My question is a very basic one:
How can I retrieve those category names from the model ?
Here is the full model:
class Category extends CActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'category';
}
public function rules() {
return array(
array('parent_id', 'numerical', 'integerOnly' => true),
array('name', 'length', 'max' => 255),
array('id, parent_id, name', 'safe', 'on' => 'search'),
);
}
public function relations() {
return array(
'users' => array(self::MANY_MANY, 'User', 'categories(category_id, user_id)'),
);
}
public function scopes()
{
return array(
'toplevel'=>array(
'condition' => 'parent_id IS NULL'
),
);
}
public function attributeLabels() {
$id = Yii::t('trans', 'ID');
$parentId = Yii::t('trans', 'Parent');
$name = Yii::t('trans', 'Name');
return array(
'id' => $id,
'parent_id' => $parentId,
'name' => $name,
);
}
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id);
$criteria->compare('parent_id', $this->parent_id);
$criteria->compare('name', $this->name, true);
return new CActiveDataProvider(get_class($this), array(
'criteria' => $criteria,
));
}
public static function getHeaderModels() {
//what sintax should I use to retrieve the models here ?
    return $models;
}
May be this answer can help you. First you must create a Widget so you can use it more effectively.
First Create a new widget. Let say the name is CategoryWidget. Put this widget under components directory protected/components.
class CategoryWidget extends CWidget {
public function run() {
$models = Category::model()->findAll();
$this->render('category', array(
'models'=>$models
));
}
}
Then create a view for this widget. The file name is category.php.
Put it under protected/components/views
category.php
<?php if($models != null): ?>
<ul>
<?php foreach($models as $model): ?>
<li><?php echo $model->name; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
Then call this widget from your main layout.
main.php
// your code ...
<?php $this->widget('CategoryWidget') ?>
...
If I'm not mistaken, you can also pass any variable available in a view, on to the layout.
You just do it from the view that has your variable.
This is the catch: you need to declare the variable which will receive your value, in the controller, like this:
<?php
class MyController extends Controller
{
public $myvariable;
After this, you will assign your model or whatever to this public variable inside your view,
like this:
$this->myvariable = $modeldata;
After you have assigned your model data to controller's public attribute,
you can easily display it inside your layout e.g.
echo $this->myvariable;
Yii already does this by assigning menu items to column2 sidebar menu, from view, like this:
$this->menu=array(
array('label'=>'List Item', 'url'=>array('index')),
array('label'=>'Manage Item', 'url'=>array('admin')),
);
You can see it in all create/update views that gii crud creates.

Categories