I am new to Yii framework. I have a task to list combined data of two tables with matching a key between two tables. I have the below table structure,
Log table
id,instance_id,user_id
Instance table
id,instance_id,instance_name
I have to show all the records from the 'Log table' in a CGridview. What I need is to display the instance_name also in that gridview.
How to set relation in these two models for achieving the result?
Assuming you have two models called Log and Instance:
In Log.php add the method:
public function relations()
{
return array(
'instance' => array(self::BELONGS_TO, 'Instance', 'instance_id'),
);
}
Add instance.instance_name to your CGridView widget.
'columns'=>array(
'id',
'instance.instance_name',
...
...
Related
I am building a backend panel for a website with Laravel Backpack. It is really nice, but I have noticed that relationship queries are very expensive.
I have two models: Product and Center with a many to many relationship between them. In my CenterCrudController I have defined a field this way:
$this->crud->addColumns([
// More fields...
[
'label' => 'Products',
'type' => 'select2_multiple',
'name' => 'products', // the method that defines the relationship in your Model
'entity' => 'products', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'model' => 'App\Models\Product', // foreign key model
'pivot' => true, // on create&update, do you need to add/delete pivot table entries?
],
// More fields...
]);
It works fine, showing a select multiple field with related models. But the query used is SELECT * FROM products, which is highly expensive (table products have thousands of records with about 25 columns).
In this example I only need id and name fields. I am looking for something like Query Builder select() method.
Is there a way for optimizing this type of query?
Thanks in advance!
Not sure if this is actually an answer, but I'll post it anyway.
The best solution (as pointed by #tabacitu) was using select2_from_ajax field. It doesn't slow page load and make an ajax request for retrieving data only when user clicks on the select field.
A table Product contains has_many relationship with a table **Slab** that further contains has_many relationship with a table Rate.
A relational query is wrapped inside CActiveDataProvider that joins three tables across certain parameters and return products in descending order of their respective rates.
I want to show the results in tabular form through CGridView.
Trying to access only certain columns through following syntax:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'name','slabs.id','slabs.rates.rate'
)
));
Unfortunately I can't access slabs.id because when I dump dataProvider object I see that it is annexed to Product object through an Array whose index[0] contains the Slab object, then under Slab object index[0] has the rates.rate object.
It is probably occurring because of the has_many relationship between tables but my query would always return one Slab and one Rate object.
How may I access and show them?
I guess there are two possible workarounds.
1. Change or add a relationship so you can access a slab and a rate with a has_one relationship.
2. You can add a column to the gridview with a custom name and value like this:
'columns'=>array(
'name',
array(
'name' => 'Slab Id',
'value' => '$data->slabs[0]->id',
),
array(
'name' => 'Rate',
'value' => '$data->slabs[0]->rates[0]->rate',
)
)
Where value is a string representing an expression to be evaluated. $data is the main model, in this case Product.
I am trying to understand how to get the model for a child class of a CActiveRecord model.
I have the following two basic classes:
Class User extending CActiveRecord
Class Tutor extending User
The connection between them is the id of the table users being a fk in table tutors. In my current app I am instanciating the User class, but I also need the data from the Tutor.
The relations were set by gii as follows:
For User class:
public function relations()
{
return array(
'tutor' => array(self::HAS_MANY, 'Tutors', 'user_id'),
);
}
For Tutor class:
public function relations()
{
return array(
'user' => array(self::BELONGS_TO, 'Users', 'user_id'),
);
}
How can I do so that I can get with an object populated with data from both models?
Note: My database tables are named at plural, while models are at singular.
When you query the active record model it should bring in the related objects automatically (provided you have set up their relationships properly). Something like the following with give you a start.
$users=User::model()->findAll();
Depending on what you are doing with the data you will need to decide if you wish to lazily fetch the related tables or eagerly fetch them. The following will eagerly fetch the records.
$users=User::model()->with('tutor')->findAll();
The Yii documentation on this subject is very good and well worth a read:
http://www.yiiframework.com/doc/guide/1.1/en/database.arr#performing-relational-query
Apparently, the siblings of an object can be accessed in Yii by simply using the following command:
$model->tutors
Where tutors represents the table corresponding to the sibling. If the relationship with the children is HAS_MANY, the command will return one or more arrays, each containing an instance of the sibling. If it is 1:1 (HAS_ONE) relationship, the command will return the object directly.
I'm quite new to Yii development and I find myself stuck at the very beginning..
In my project I have a table with two columns both pointing to an external table.
Something like:
table "item":
- user_id_1
- user_id_2
table "user":
- id
So an item i always associated with two users, but I do not want to differentiate them, and I want to be able to do something like
$item->users
getting both the users.
And also the opposite:
$user->items
getting all items that reference the user id in user_id_1 or user_id_2.
Does this sound right? Any suggestion?
Yii's ActiveRecord is really only set up to handle one-to-one and one-to-many relationships - you seem to be describing a one-to-two relationship.
One way to handle this would be to set up a MANY_MANY relationship, but just use it with two users instead of "many". You will need to set up a user_item table that connects Users to Items, instead of embedding the key directly in the tables. If you need to enforce only two Users-to-an-Item you'll need to write some extra Validation code in your Item model. The relation in Item will look something like this, and you will be able to call $item->users like you want:
public function relations() {
return CMap::mergeArray(parent::relations(),array(
'users'=>array(self::MANY_MANY, 'User', 'user_item(item_id,user_id)'),
));
}
The new associative table will look like this:
user_item:
-- user_id
-- item_id
If you really need to use two separate user_id foreign key fields like you have here, you will need to set up an ActiveRecord HAS_ONE relation for each, like so:
public function relations() {
return CMap::mergeArray(parent::relations(),array(
'user1' => array(self::BELONGS_TO, 'User', 'user_id_1'),
'user2' => array(self::BELONGS_TO, 'User', 'user_id_2'),
));
}
But, you can still enable the $item->users call syntax with a function something like this, which will return both users in a single array:
public function getUsers() {
return array(
$this->user1,
$this->user2,
);
}
This takes advantage of Yii's __get() method override, which will allow you to call $item->getUsers() like $item->users.
You can set up something similar in the User model, with two HAS_MANY relations for user_id_1 and user_id_2, and a getItems method which returns the merged result arrays.
But I think the easiest option will be to set up a MANY_MANY relationship (and use it a ONE_TWO relation).
I have the following relation scheme:
1 portfolio -> Many Users in each Portfolio -> Each User owns many Products
Entities: Portfolio, User, Products
What I would like to display is in one page:
1. The name of the portfolio
2. The title of a user
3. CGridView of all products owned by that user
It seems, if CGridView were not being used, you would populate your model appropriately and then use a foreach loop to loop through each user relation and then loop through the products related to that user. And create a render_partial view for the products and for the user.
However, I am at a complete loss as how to accomplish this with CGridView.
Any advice is much, much appreciated!
You want to render the User's Products in a CGridView?
To render data with a CGridView you need to pass in a CDataProvider to populate the view. So the question is: how do you make a CDataProvider for the HAS_MANY relation?
Surprisingly, the CActiveDataProvider does not support relations in this way. What you need to do get the relation and pass that data into a CArrayDataProvider. Assuming the $user->productsrelation,you can do it like this:
$dataProvider = new CArrayDataProvider($user->products, array());
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'id', // your columns here
),
));
It's not ideal, but it works. Credit goes here for this specific technique: http://learnyii.blogspot.com/2010/12/yii-how-to-display-related-hasmany-grid.html