Using Many to Many relations in yii - php

I am currently trying to display/retrieve data from my database using Yii framework relations which were auto generated by Gii. (MANY_MANY)
User Model contains:
return array(
'memberOfTeams' => array(self::MANY_MANY, 'UsersTeam', '{{teamMembers}}(userId, teamId)'),
);
UserTeam Model contains:
return array(
'teamMembers' => array(self::MANY_MANY, 'User', '{{teamMembers}}(teamId, userId)'),
);
Currently I am working on the User view called profile.php . All I am trying to accomplish is to display the current user with all the teams assigned to him.
teamMembers contains teamId and userId.
How would I write this query?
I have this currently
<?php echo CHtml::dropDownList("teamName", 'id', Chtml::listData(UsersTeam::model()->with('teamMembers')->findAll(teamMembers.userId, array($model->id)), 'id', 'teamName'),array('empty'=>'Select Team')); ?>
I am able to get all the information if I use findAll(), but I want only teams that the user is assigned to.

A project of mine does something similar:
MANY_MANY relation between shop and card, this dataprovider is used to display a list of shops linked to a specific card:
$shopDataProvider=new CActiveDataProvider( 'Shop',
array(
'criteria'=>array(
'with'=>array('cardShop'),
'condition'=>'cardShop.card_id=:cardId',
'params'=>array(':cardId'=>$id),
'order'=>'t.id DESC',
'together'=>true,
),
)
);

Related

is it possible to display content from cgridview to dropdown in yii?

I have modified my model so that the data displayed in cgridview is unique per user, depending on the account type...
However I need to create a form from another model where I could get the data from the cgridview via dropdown...
I used this code at first...
<?php
$this->widget('ext.select2.ESelect2',array(
'model'=>$model,
'attribute'=>'pr_id',
'data'=>$model->searchPatient(),//function to provide data
// or
//'data'=>CHtml::listData(PatientRecord::model()->findAll(), 'id', 'first_name')
);
?>
but it returns all of the contents of the PatientRecord model, I tried using a condition before planning to retrieve the contents from the cgridview...
$doctor= Yii::app()->user->id;
CHtml::listData(PatientRecord::model()->findAll( array(
'condition'=>'doctor_id=:doctor_id',
'params' => array(':doctor_id' => $doctor)
)
);), 'id', 'first_name')
it didn't have an error but it didn't display anything on the dropdown either...
any suggestions?
I think the problem is with a ; and ) in your model code, try this:
$doctor= Yii::app()->user->id;
CHtml::listData(PatientRecord::model()->findAll( array(
'condition'=>'doctor_id=:doctor_id',
'params' => array(':doctor_id' => $doctor)
)
), 'id', 'first_name');
You should always enable error logging in local environment, this will help you find any errors in your code. Here is a link on how to enable error logging.
Hope that helps :)

Yii CGridView, displaying multiple columns from related model with filtering capability

I'm pretty new to yii and I bumped into the following problem. I have 2 related tables, ClientTicket and Product with the following structure:
ClientTicket
id
ticket_name
client_id
product_id
Product
id
type
model
brand
The two tables are related through a foreign key which binds ClientTicket.product_id to Product.id.
The Problem
In the admin view of the ClientTicket I've managed to include two of the Product columns (brand, model) and have the search box display for each of them, but the filtering isn't working as expected. Ex: When I search in either of the two search boxes(brand, model), the other one populates automatically with the same value I typed (so no search results).
The ClientTicket 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(
'product' => array(self::BELONGS_TO, 'Product', 'product_id'),
........
);
}
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
...
$criteria->compare('product.model',$this->product_id, true);
$criteria->compare('product.brand',$this->product_id, true);
...
$criteria->with=array(..., 'product',);
$criteria->together= true;
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination' => array('pageSize' => 10),
));
}
The ClientTicket Admin view file:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'client-ticket-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'ticket_number',
'ticket_date',
array('name'=>'agent_id',
'header'=> 'Agent',
'value'=> '$data->ticket_agent->name',
'filter'=>CHtml::listData(Agent::model()->findAll(), 'name', 'name'),
),
...
array('name'=>'product_id',
'header'=> 'Product',
'value'=> '$data->product->model',
),
array('name'=>'product_id',
'header'=> 'Brand',
'value'=>'$data->product->brand'
),
Your productand brand columns both have the same name but different values. The filter obtains the field name from name unless you explicitly state it i.e create your own active field. In addition you are using the same attribute product_id to search both fields in your search function.
How to filter using related models has been answered at Yii - how can I search by a column from foreign/related key on admin page?
For other users reference, here's how i got it to work.
Again, Thank you topher for the prompt response. :)
Inside ClientTicket model:
declared a new public variable named $brand
added 'brand' to 'safe' 'on'=>'search' array, inside of rules() function
added a new criteria inside the search() function like so:
$criteria->compare('product.brand',$this->brand, true);
In the ClientTicket admin view file:
modified the product brand column from this:
array('name'=>'product_id',
'header'=> 'Brand',
'value'=>'$data->product->brand'
),
to this:
array('name'=>'product.brand',
'header'=> 'Brand',
'filter'=>CHtml::activeTextField($model,'brand'),
),

Need help to create CRUD screen with dropdown (relation) using yii-framework

I need to create CRUD screen using yii-framework. Simple CRUD screen using one table is working perfectly fine. I'm facing problem/issue while using dropdown (linking table).
I have installed giix extension which is suppose to create CRUD with dropdown if FK is specified but I dnt have MySql Engine InnoDB on my hosting provider, so I'm not able to use that extension. I need to do it manually.
I have two tables
main:-
id
store_id
prefix
store:-
id
name
Now store_id of main is FK to id of store table. And I want to create CRUD for main table.
So that Add Screen should show:-
Store Name:- Dropdown
prefix:- Textbox
View screen should use name column of store table instead of showing store_id
Thanks in anticipation.
Generate CRUD using Gii, then read my blog. http://jmmurphy.blogspot.com/2013/05/using-yii-model-relations.html
Basically you will have something like this for your store_id field after Gii Generation
<?php echo $form->labelEx($model,'store_id'); ?>
<?php echo $form->textField($model, 'store_id', array('size'=>60,'maxlength'=>255));?>
<?php echo $form->error($model,'store_id'); ?>
The textField line is replaced by:
<?php $list = CHtml::listData(Store::model()->findAll(), 'id', 'name'); ?>
<?php echo $form->dropDownList($model, 'store_id', $list, array('empty'=>'(Select a Store)')); ?>
You also need to define relations in your Main model so that you can access related tables (even if your database does not support foreign keys) like this:
public function relations()
{
return array(
'store'=>array(self::BELONGS_TO, 'Store', 'store_id'),
);
}
And to complete this relation, you should also add the following relation to your Store model:
public function relations()
{
return array(
'main'=>array(self::HAS_MANY, 'Main', 'store_id'),
);
}
These relations define a One to Many relation between Store and Main where store is the parent, and Main is the Child. To make it a One to One relationship change HAS_MANY to HAS_ONE. The HAS_* goes in the parent model and points to the foreign key attribute in the child table. The BELONGS_TO goes in the child and tells the attribute in the child table that points to the primary key in the parent.
Now to see the store name in the view action, you need to change 'store_id' in your view.php to an array that looks like:
array(
'name' => 'store_id',
'value' => $model->store->name,
)
The admin view is slightly different. I am not sure exactly why, but to view the store name instead of the id in the admin view you will need to use an array that looks like:
array(
'name' => 'store_id',
'value' => '$data->store->name',
)
Note that Gii generates this so that $data is the model instead of $model, and also it does a funky double indirection thing so that you need to put the variable declaration in single quotes.
Thanks jmarkmurphy for your help. You helped me lot and I have marked your answer as correct only as you gave me guidance. Just posting exact code in detail.
I changed view.php with below code:-
<?php $this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>array(
'id',
'store.name',
'prefix',
),
));
Also changed admin.php with below code:-
<?php echo CHtml::encode($data->store->name); ?>
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'main-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'store.name',
'prefix',
array(
'class'=>'CButtonColumn',
),
),
)); ?>
Thanks once again jmarkmurphy. Thanks a lot . My application is now working and exactly the way I wanted.

Using CGridView to show another model's attributes

I have the database just like this
==== Group =====
id
name
==== Member ====
id
group_id
firstname
lastname
Now I can use Member member's table attributes in group controller just by using multimodel.
As I have done multimodel so I can easily make create update delete for both models from a single view page. Now my problem is when I am going to shoew both models in Group's admin view file I have to show both files in CGridView to show in a Grid. But my problem is in CGridView only first model can be seen.I want the second models to be shown on the CGridView. So how to do that?
I think you need to combine models using the Relational Active Record.
In the process of self learning I'm following, I hope I will shortly have an example to post here...
EDIT finally, I worked out an example. I've (maybe) found a bug in Yii, so what is an easy task, required more time than necessary...
I have two models, User e Persona, obtained from gii, previously unrelated. Then I add a Persona to User as optional attribute: in User.php
/**
* #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(
'persona' => array(self::HAS_ONE,'Persona','id')
);
}
then the model for User automatically display selected fields from Persona, when bound to CGridView:
<hr><?php
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => new CActiveDataProvider('User'),
'columns' => array(
'username',
'password',
'email',
'persona.indirizzo'
),
));
?>
The bug I found (perhaps, need to investigate more): my Persona model has an attribute with an accented character in name, and if I use that instead I get an error: i.e. if
'columns' => array(
'username',
'password',
'email',
'persona.identità'
),
then the page can't be instanced:
The column must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.
/home/carlo/public/yii-1.1.8.r3324/framework/zii/widgets/grid/CGridView.php(332)
320 foreach($this->columns as $column)
321 $column->init();
322 }
323
324 /**
325 * Creates a {#link CDataColumn} based on a shortcut column specification string.
326 * #param string $text the column specification string
327 * #return CDataColumn the column instance
328 */
329 protected function createDataColumn($text)
330 {
331 if(!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/',$text,$matches))
332 throw new CException(Yii::t('zii','The column must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));
333 $column=new CDataColumn($this);
334 $column->name=$matches[1];
I think it's the regular expression that mismatch...
If you add getters for groupId and groupName to the Member model you can easily display the gridview for members and include their group data. It's not an extremely clean solution, but it's the easiest.
Define some function like 'getGroupNameById' in group model then call it as follows
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider, //for members model
'columns'=>array(
'id',
'firstName',
'lastName',
array(
'name'=>'groupName'
'value'=>'getGroupNameById($data->group_id)',
//$data is members row accessible in gridview
),
),
));
Check this post for more details CGridView-Render-Customized-Complex-DataColumns

Yii Framework - CGridView sort related columns

Thanks in advance to anyone who can help. I've been searching for an answer, but haven't found one yet. I've run into "solutions" that haven't worked that run from 1 line, to re-writing an entire class.
I've got the "grid" to show the relation, and am able to use the search feature. What I can't figure out is the sort feature. The column header becomes non-clickable once the below changes have been made.
This is what I have:
The relation name/label is "company," setup in Employee model.
Table: Employee -- Column: idCompany
&
Table: Company -- Column: companyNick
admin.php - VIEW
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'employee-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'company',
'value'=>'$data->company->companyNick',
),
'lastName',
'firstName',
ETC...
Employee.php - MODEL
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
//Company Relation Search
$criteria->compare('company.companyNick',$this->company,true);
$criteria->with='company';
//stock
$criteria->compare('idEmployee',$this->idEmployee,true);
$criteria->compare('idAccount',$this->idAccount,true);
ETC...
I've been having the same problems and in the end solved it this way:
Model Search method:
$sort = new CSort();
$sort->attributes = array(
'assignedTo'=>array(
'asc'=>'(SELECT surname from people
WHERE people.person_id = t.assigned_to) ASC',
'desc'=>'(SELECT surname from people
WHERE people.person_id = t.assigned_to) DESC',
),
'*', // add all of the other columns as sortable
);
View file:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'tasks-grid',
'dataProvider'=>$model->search(),
//'filter'=>$model,
'columns'=>array(
'task',
array(
'header'=>'Assigned To',
'value'=> '$data->assignedTo->surname.", ".$data->assignedTo->forename',
'name'=> 'assignedTo',
'sortable'=>TRUE,
),
'due_date',
'status',
),
));
This way I'm selecting a single field from the related table into the order by clause and then ordering by that, you create the table join in the expression, in this case it is -people.person_id = t.assigned_to (where t is a table alias provided by yii). This is perhaps not the most efficient way to create the order by clause but it works!
This seems to be a daily question on [yii]. Strip that stuff out of your search function, and add a filter attribute to your CGridView column like so:
array(
'name'=>'company',
'value'=>'$data->company->companyNick',
'filter' => CHtml::listData(Company::model()->findAll(),'id','nick'),
),
There is also good explanation how to do this on Yii web site Wiki page:
http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview/
I like Mike H's answer. I also want to point out that you could, instead of entering the raw SQL, use with() to perform a relational query and then set select to false to prevent actually loading the related models. You can also use the related attribute's attributeLabel in the view by passing the dot-notated string, e.g.,:
// Controller
$gridDataProvider = new CActiveDataProvider('EmrFormPatientTie', array(
'criteria'=>array(
'condition'=>'flag_locked=0',
'with'=>array('patient'=>array(
'select'=>false, // Perform relational query without loading related models
)),
),
'pagination'=>(array('pageSize'=>15)),
'sort'=>array(
'attributes'=>array(
'patient.display_id'=>array(
'asc'=>'patient.display_id',
'desc'=>'patient.display_id DESC',
),
'*', // Make all other columns sortable, too
),
),
));
// View
array(
'name'=>'patient.display_id',
'value'=>'$data->patient->display_id',
),

Categories