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.
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.
i have a model setup in Eloquent of a many to many relationship of Pages and Articles. My users have the ability to order these articles per page.
So my question is, can i order the relationship with sync...
$page->articles()->sync($specificOrderOfArticleIds)
And it sync the relationships in the order of that passed array.
so when i query the page
$page->articles() // in specified order
It's in the specified order.
Maybe i'm missing something obvious here?
In order to do that, you'll need some kind of column in the pivot table that defines an order. For example, an "order" column on the pivot table could be given a value using:
$page->articles()->sync([1 => ["order" => 1], 42 => ["order" => 6]]);
Then on the read, you can pass a closure into your query to specify the order be by this column.
$page = Page::whereId($id)->with(['articles' => function($query) {
$query->orderBy('pivot.order', 'asc');
}])->get();
The "pivot" keyword is used in relationship queries to point to the middle table.
However, you can use the closure ability shown above to order by anything you like, not just the pivot table. Depending on how you define the order, you may not even need the new pivot table column.
I'm trying to create a database (using MySQL) for a simple Yii-based website. It will contain a catalog with goods, which are divided into a few categories. The idea is to have a way to add additional fields, specific for each category, and these fields should be fillable for each good in a category.
For example, if I have a category 'wallpapers', they should have additional fields 'color', 'footage', 'facture' etc. An of course these fields must be filled differently for each wallpaper item.
I created a database with 4 tables for it: items (which contains items, obviously), items_categories (with categories for therm), items_fields (contains additional fields) and items_fields_values (a support table for many-to-many relationship which also contains a values of related fields).
My database schema diagram (you need to have at least 10 reputation to attach images).
I'm using Yii Framework, and relationships in models described in a such way:
Item model:
return array(
'category' => array(self::BELONGS_TO, 'ItemCategory', 'category_id'),
'fields' => array(self::MANY_MANY, 'ItemField', 'items_fields_values(item_id, field_id)'),
);
ItemField model:
return array(
'itemCategory' => array(self::BELONGS_TO, 'ItemCategory', 'item_category_id'),
'items' => array(self::MANY_MANY, 'Item', 'items_fields_values(field_id, item_id)'),
);
ItemCategory model:
return array(
'items' => array(self::HAS_MANY, 'Item', 'category_id'),
'itemsFields' => array(self::HAS_MANY, 'ItemField', 'item_category_id'),
);
How should I define these relationships to have a way to output, add and edit fields to category and their values to specific items?
What you are describing is an EAV data model (entity-attribute-value).
An extension might solve your problem for accessing the data. Take a look at https://github.com/yiiext/eav-behavior
I have a model User and a model Role in a CakePHP application. The association between the two models is the following:
User $belongsTo Role
Role $hasMany User
I want to make a query on the User model to find all users with a specific role (let's say the role Supervisor). I did my query like this:
$supervisors = $this->User->find('all', array(
'contain' => array(
'Role' => array(
'conditions' => array(
'Role.name' => 'Supervisor'
)
)
)
));
But the above query returns me all the users in my users table. It does not return only the users with role Supervisor. I know that if I do two queries, one on the Role model to find the id of the role type 'Supervisor' and then do another query on the User model and pass the id of the supervisor role record in the conditions on my User model like this:
$supervisor_role_id = $this->Role->field('id', array('Role.name' => 'Supervisor'));
$supervisors = $this->User->find('all', array(
'conditions' => array(
'User.role_id' => $supervisor_role_id
)
));
The above queries will give me the desired result. But I don't wanna do 2 queries to do this. Why doesn't the first approach work. Any idea please?
Thank you
The reason your attempt didn't work
CakePHP's Containble Behavior creates separate queries for each model. So - what you did was basically described like this: "Find all Users. Also find any Roles with the name of 'Supervisor". As you can see, there is no condition that crosses between the two.
So, you can do one of the following:
1) [easy way] Query the other way around
Query from the Role model and contain it's user(s). This pulls the role you want (based on your provided conditions) then contains any/all of it's users.
Note - if you've already loaded the 'User' model (or it's been loaded by default because you're in the UsersController), you can run your find like this: $this->User->Role->find(..... - so you don't have to load the Role model separately.
2) Use JOINs (see CakePHP Book on Joining Tables)
This allows you to limit the result of a parent model based on it's associated data.
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',
...
...