YII dataProvider relation CDbCriteria - php

I have a problem regarding the use of CDbCriteria in a controller index action. I have 2 classes: event and attendee.
the class event has many attendee, and i want my event index action to render only the list of events of which the current loggedin user is an attendee...
$criteria = new CDbCriteria(array(
'order'=>'event_date desc',
'with' => array('attendees'=>array('alias'=>'attend')),
'condition'=>'attend.uid = ' . Yii::app()->user->id,
));
$dataProviderAtt=new CActiveDataProvider('Event',
array(
'criteria' => $criteria,
)
);
$this->render('index',array(
'dataProvider'=>$dataProviderAtt,
));
this does not work in DB with the message:
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'user'
my relations in attendee class are set like this:
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(
'user' => array(self::BELONGS_TO, 'YumProfile', 'uid', 'alias'=>'user'),
);
}
I tried to change the defaultscope in attendee model and define multiple aliases:
public function defaultScope()
{
static $counter = 0;
return array(
'with' => array('user'=>array('alias'=>'user'.($counter++))),
//'with' => 'user',
'order' => 'score DESC',
);
}
but it does not seem to fix the issue and I then have more errors. Is my criteria correctly set?
Thx guys for your help

you are looking for
'on' => 'attend.uid = ' . Yii::app()->user->id,
as in your relation to the user
function relations()
{
return array(
'user' => array(
self::BELONGS_TO,
'attendees',
'',
'on' => 'attendees.uid = ' . Yii::app()->user->id,
),
);
}

Related

Yii scopes with multi-table relations

I have a model Order with one-to-many relationship to model Booking. Booking model, in turn, has a Connection model reference.
I'm having trouble figuring out how to scope out Order so that I only get the order that have bookings with Connection.isDefault value set to 0.
I may have many Bookings with the Order, so I need to look through the very first booking.
I feel this may not be achievable through the scope mechanism as I cannot pass Order/Booking primary keys through helper functions that can be used in scope. What is an alternative workaround here (if any) can you suggest?
The Order has a code for scopes:
public function scopes()
{
return array(
'canView' => array(
'with' => array(
'agency' => array(
'scopes' => array('myNetwork', 'myCompany' => 'OR')
)
),
),
'canEdit' => array(
'with' => array(
'agency' => array(
'scopes' => array('myNetwork', 'myCompany' => 'OR')
),
),
),
);
}
Please try using CDbCriteria(). add relation in Bookings table and order table.
The Bookings has a code for relation:
class Bookings extends CActiveRecord{
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(
'connectionRel' => array(self::BELONGS_TO, 'connection', 'booking_id', "condition" => 'isDefault = 0'),
);
}
}
The Order has a code for relation:
class Order extends CActiveRecord{
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(
'bookingsRel' => array(self::BELONGS_TO, 'Bookings', 'booking_id', "with" => array('connectionRel')),
);
}
}
Find all order with booking relation :
Order::model()->with('bookingsRel')->findAll();
Try using CDbCriteria(). In with you can put relation and it there do again with (do some CDbCriteriaCeption). Try experimenting with other criteria params to fit your needs (like applying $c->together = true;)
$c = new CDbCriteria();
$c->with = [
'bookings' => [
'select' => false,
'with' => [
'connections' => [
'select' => false,
]
]
]
];
$c->addCondition('connections.isDefault = 0');
Order::model()->findAll($c);

CakePHP recursive not working with conditions

I have a problem with querying associated data from a Model in CakePHP. I wrote an example to show the behavior:
TestController.php:
class TestController extends AppController
{
public $uses = array(
'User',
'Upload',
'Detail'
);
public function test(){
$result = $this->Upload->find('all', array(
'recursive' => 2,
'conditions' => array('Detail.id' => 1)
));
print_r($result);
}
}
Upload.php:
class Upload extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
}
Detail.php:
class Detail extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
}
User.php:
class User extends AppModel {
public $hasOne = 'Detail';
public $hasMany = array(
'Upload' => array(
'className' => 'Upload',
'foreignKey' => 'user_id',
)
);
}
When I remove the condition I get back an array with Details included. But with the condition I get the following error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Detail.id' in 'where clause'
Looking at the SQL Queries it seems like he is not joining the tables correctly when I add the condition. Without the condition he is joining all three tables.
Is this a bug in CakePHP or am I doing anything wrong?
No, it is not a bug with CakePHP. It's simply the way it's designed, using conditions during a find on associated models will often create an invalid query. You should be using containable behavior or manually joining to use conditions on associated models.
Also, I suspect that you will not get the results you are looking for doing this way anyways. CakePHP by default uses left joins. Therefore, your results will not be limited by those associated with the desired Detail ID, but rather, it will get all uploads, all users associated with those uploads, and then only those details associated with those users that have the correct ID. The simplest way then to get what you're probably looking for is to do the query from the opposite direction:
$result = $this->Detail->find('all', array(
'recursive' => 2,
'conditions' => array('Detail.id' => 1)
));
EDIT: If you do want to do left joins, then make your query this way:
$result = $this->Upload->find('all', array(
'contain' => array('User' => array('Detail' => array('conditions' => array('Detail.id' => 1))),
));

Displaying attributes from another model using CGRIDVIEW

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.)

Searching and sorting by related model in Yii with CGridView when Relation is a key in the same table

There is a comprehensive article about searching and sorting by related model in CGridView here: http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview/ I've successfully implemented this recipe a number of times.
However, now I am trying to search and sort by a relation that is in the same table (it defines the parent_id). See 'parent' relation below:
public function relations()
{
return array(
'parent' => array(self::BELONGS_TO, 'Category', 'parent_id'),
'children' => array(self::HAS_MANY, 'Category', 'parent_id'),
'childCount' => array(self::STAT, 'Category', 'parent_id'),
'author0' => array(self::BELONGS_TO, 'User', 'author'),
'contents' => array(self::MANY_MANY, 'Content', 'content_category(content_id, category_id)'),
'crsContents' => array(self::MANY_MANY, 'ContentCrs', 'content_category(content_id, category_id)'),
);
}
public function defaultScope()
{
return array(
'alias'=>'cat',
'order'=>"cat.name ASC",
);
}
When I implement the method as specified by the wiki, I get the following error:
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'cat'. The SQL statement executed was: SELECT COUNT(DISTINCT `cat`.`id`) FROM `category` `cat` LEFT OUTER JOIN `category` `cat` ON (`cat`.`parent_id`=`cat`.`id`) WHERE (cat.parent_id <> 257)
How can I ensure that the LEFT OUTER JOIN uses a unique table alias such as parent for the relation so that I can properly define my CDbCriteria in search()
EDIT:
As requested by #tereško, here is my search() function. I know it is flawed due to the table alias parent specified when I have not defined it... I just don't know how!
public function search()
{
$criteria=new CDbCriteria;
$criteria->with = array('parent');
$criteria->compare('id',$this->id,true);
$criteria->compare('author',$this->author,true);
$criteria->compare('name',$this->name,true);
$criteria->compare('description',$this->description,true);
$criteria->compare('parent_id',$this->parent_id,true);
$criteria->compare('parent.name', $this->parent_search, true );
$criteria->compare('type',$this->type,true);
$criteria->compare('slug',$this->slug,true);
$criteria->compare('created',$this->created,true);
$criteria->compare('updated',$this->updated,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'parent_search'=>array(
'asc'=>'parent.name',
'desc'=>'parent.name DESC',
),
'*',
),
),
)
);
}
You can give alias to parent relation as below
$criteria->with = array(
'parent'=>array(
'alias'=>'parent'
)
);

yii "Trying to get property of non-object" at view.php

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

Categories