Guardian model:(relation)
'studentsGuardians' => array(self::HAS_MANY, 'StudentsGuardian', 'guardian_id'),
Student model relation:
'studentsGuardians' => array(self::HAS_MANY, 'StudentsGuardian', 'student_id'),
Students Guardian model relation:
'guardian' => array(self::BELONGS_TO, 'Guardian', 'guardian_id'),
'student' => array(self::BELONGS_TO, 'Student', 'student_id'),
Now in controller i want to select those students whose guardian_id=id but my code select all records without filtering. my code is
public function actionAssignGuardian($id)
{
$dataProvider = new CActiveDataProvider('Student',
array(
'criteria' => array(
'with'=>array('studentsGuardians',
array('criteria'=>
array('with'=>array('guardian','condition'=>' guardian_id=:id',
'params'=>array('id'=>$id))))),
),
));
$this->renderPartial('Pages/_assignGuardian', array(
'dataProvider' => $dataProvider,
'id'=>$id,
));
}
Kindly point me to correct way that how could i select those students whose guardian_id= given id in function. I am new to yii.
Thanks.
Add this line into Student model (below previous relation line studentsGuardians)
'guardians' => array(self::HAS_MANY, 'Guardian', array('guardian_id'=>'guardian_id'),'through'=>'studentsGuardians'),
Then you can do query like this
$dataProvider = new CActiveDataProvider('Student',
array(
'criteria' => array(
'with'=>array(
'guardians' =>array(
'condition'=>' guardian_id=:id',
'params'=>array('id'=>$id)
)))
));
(You should also dump $id to make sure that it is valid value)
Related
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);
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))),
));
I want to show 2 tables with a right join, but the code I wrote does not work as expected. Can anyone tell me what I am doing wrong ?
view : admin.php
$this->widget('bootstrap.widgets.TbGridView', array(
'id' => 'punish-grid',
'dataProvider' => $model->searchJoin(),
'type' => 'striped bordered condensed',
'filter' => $model,
'columns' => array(
array(
'header' => 'No',
'type'=>'raw',
'htmlOptions'=>array('style'=>'width: 25px'),
'value'=>'$this->grid->dataProvider->pagination->currentPage
*$this->grid->dataProvider->pagination->pageSize + $row+1',
),
// i want to display p.kode,p.status from table status
'berlaku_punish',
'nilai',
array(
'class'=>'bootstrap.widgets.TbButtonColumn',
),
),
));
and my model : BasePunish.php
public function relations() {
return array(
'idStatus' => array(self::BELONGS_TO, 'Status', 'id_status'),
);
}
public function searchJoin() {
$criteria = new CDbCriteria;
$criteria->select = 'p.kode,p.status,t.nilai,t.berlaku_punish';
$criteria->join= 'RIGHT JOIN status p ON (t.id_status=p.id)';
$criteria->condition = 't.id_status IS NULL';
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'sort'=>array(
'defaultOrder'=>'kode ASC',
),
)
);
}
I might really did not understand what you are asking but still if nothing is working for you then you can try this
array(
'header'=>'Products',
'value'=>array($model,'gridCreateUser'),
),
In this, the value will try to find the function gridCreateUser in the class of which $model is the object. In your case i guess $model is the object of the BasePunish.
So in your BasePunish.php create a function gridCreateUser() and then you can return the value which you want to display in your widget.
eg:-
In your BasePunish.php
public function gridCreateUser($data)
{
// you can access the object $data here
// do what ever you want to do
$value='return whatever you want to return';
return $value;
// this $value will be displayed there
}
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!
Ok this is kind of hard to explain but I'll try my best.
I have 3 tables
companies products product_availabilities
--------- -------- ----------------------
id id id
name name company_id
product_id
buys (tinyint)
sells (tinyint)
And their models
class Company extends AppModel
{
public $name = 'Company';
public $hasMany = array(
'ProductAvailability'
);
class Product extends AppModel
{
public $name = 'Product';
public $hasMany = array(
'ProductAvailability'
);
class ProductAvailability extends AppModel
{
public $name = 'ProductAvailability';
public $belongsTo = array(
'Company',
'Product'
);
}
What I want to do is when I create a company, I want to be able to select products that the company buys or sells. I've seen an example of a hasMany through relationship in the book (http://book.cakephp.org/1.3/view/1650/hasMany-through-The-Join-Model) but they are creating the form from the "join table" controller. Is it possible to bind the productAvailability model to my company model to be able to select the products while creating the company?
Edit : Here is how I've done it. I know it is not optimal as there is a lot of looping involved but it works.
Company controller :
$products = $this->Company->ProductAvailability->Product->find('list', array('fields' => array('Product.id', 'Product.label')));
$this->set('products', $products);
if($this->request->is('post')){
if($this->Company->save($this->request->data)){
foreach($products as $product)
{
$tmpArray = array(
'company_id' => $this->Company->id,
'product_id' => $product['Product']['id']
);
foreach($this->request->data('BuyProducts.product_id') as $buyProduct)
{
if($buyProduct == $product['Product']['id'])
$tmpArray['buys'] = 1;
}
foreach($this->request->data('SellProducts.product_id') as $sellProduct)
{
if($sellProduct == $product['Product']['id'])
$tmpArray['sells'] = 1;
}
if(count($tmpArray) > 2)
{
$this->Company->ProductAvailability->create();
$this->Company->ProductAvailability->set($tmpArray);
$this->Company->ProductAvailability->save();
}
}
$this->Session->setFlash('Yay', 'success');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Nay', 'error');
}
}
Company add form :
<?php echo $this->Form->create('Company'); ?>
<?php echo $this->Form->input('name', array( 'div' => 'full-form')); ?>
<?php echo $this->Form->input('BuyProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->input('SellProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->end(array('label' => __('Save'), 'div' => 'center', 'class' => 'bouton-vert')); ?>
You have two options. Either let cakePHP do some magic with the hasAndBelongsToMany relationship or doing it manually which is necessary if you add attributes to the join table
1. CakePHP HABTM
Using the capabilities of CakePHP and making a straight forward solution I would make these changes:
Model
If one company has more than one product, and the products belong to many companies. It is a hasAndBelongsToMany relationship between Company<->Product
// company.php
...
var $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'companies_products',
'foreignKey' => 'company_id',
'associationForeignKey' => 'product_id',
'unique' => true,
)
);
...
// similar in product.php
Add the required table 'companies_products' in the database.
Controller
Then in the add function from the Company Controller there should be something like:
$products = $this->Company->Product->find('list');
$this->set(compact('products'));
View
Finally insert the products in the add.ctp, the select should allow multiple selections and let cakePHP do some magic, like this:
echo $this->Form->input('products', array(
'label' => 'Products to buy (Ctr+multiple choice)'
'type' => 'select',
'multiple' => true,
));
2. Manually
When the HABTM becomes more 'exotic' and includes some attributes like in your case 'buy' or 'sell' you need to do the manual way. This is in the Product Controller setting manually the fields before inserting them in the database. Something like:
foreach($availableProducts as $availableProduct ){
$this->Product->ProductAvailabilities->create();
$this->Product->ProductAvailabilities->set( array(
'company_id' => $this->Product->id,
'product_id' => $availableProduct['Product']['id'],
'buys' => $availableProduct['Product']['buy'],
'sells' => $availableProduct['Product']['sell']
// or however you send it to the controller
));
$this->Product->ProductAvailabilities->save();
}
Let's hope this helps you ...
you are planning a habtm-relationship (m:n) with the possibility to have extra fields in the join table. Even though this can be done with regular habtm I prefer the way you choose and implement the m:n as 1:n:1, which is simply the same and gives you more options when saving your data.
Here is a similar question and answer
As for your question: You can collect the the data from your products table like this:
$this->Company->ProductAvailability->Product->find('all', $params);
Also you might want to have a look at the containable-behaviour which is very useful for this use case:
$params['conditions'] = array(
'Company.id' => $id
);
$params['contain'] => array(
'ProductAvailability' => array(
'conditions' =>array(
'buys' => 1
),
'Product' => array(
'order' => array(
'name' => 'ASC'
)
)
)
);
$this->Company->find('all', $params);