Laravel-Backpack Getting data of 2 tables by join - php

I'm new using backpack for laravel and I'm trying to understand how could show data from DB in the default view that backpack use to display rows. I already read the documentation from the site but it's really poor, and have a lot of questions.
I have 2 models linked by join, for example:
Table 1 Table 2
-id -id
-name -phone
-age -description
-table2_id
How can I display the attributes from table 2 in table 1 list view?. Backpack haves this view to list elements of modules
I want to see on that table the combination of the 2 tables...Any code that could help me ?. Thank you for your help.

Backpack creates CRUD Panels for you Eloquent Models. Not your database tables. So in order to have columns showing up that show elements from another table, you need to properly define the relationships between those Models. Then you can use the select column to show that connected entry.

[
'name' => 'rm_id',
'label' => 'Relationship Manager',
'type' => 'select2',
'model'=>config('permission.models.role'),
'options' => (function ($query) {
return $query->where('roles.name', 'Relationship Manager')
->join('model_has_roles', 'model_has_roles.role_id','=','roles.id')
->join('users', 'model_has_roles.model_id','=','users.id')
->select('users.id','users.name')->get();
}),
'attribute'=>'name',
],

Related

CakePHP 2.X - Couple of questions on HasMany Relation

I'm having some problems using this old framework I had to manage.
I have these tables:
GROUP -> HAS MANY -> MONITOR
MONITOR -> HAS MANY -> [ EVENTS , ZONE ]
MONITOR -> HAS_AND_BELONGS_TO_MANY -> GROUP
For GROUP -> MONITOR Relationship, a join tables has been created by Cake called GROUP_MONITOR.
This is the HasMany Configuration on Group Model:
'Monitor' => array(
'className' => 'Monitor',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'GroupId',
'associationForeignKey' => 'MonitorId',
QUESTION 1:
I'm trying to retrieve all groups with all the related monitors. I found the recursive key that allow to go deeply in relations:
$all_groups = $this->Group->find('all', array('recursive' => 1));
I got this error:
Column not found: 1054 Unknown column 'Monitor.GroupId' in 'field list'"
It seems like Cake is not using the "Groups_Monitors" table but is searching groupId in the Monitor Table;
QUESTION 2:
Trying to get Groups querying Monitors, with recursive to 1 I got all groups correctly but also all other Monitor's HasMany relations.
$all_monitors = $this->Monitor->find('all',array("recursive" => 1));
Is it possible to exclude some HasMany relations in find to have a reduced amount of data?
You say you have
GROUP -> HAS MANY -> MONITOR
"Has many" doesn't use a join table. The way this relation works is "monitor" has to have a foreign key that references a group. If you want to use the join table you should use "has and belongs to many".
For Q2, use the containable behavior. You'll be able to specify in detail what data and which models you want fetched from the DB. https://book.cakephp.org/2/en/core-libraries/behaviors/containable.html

CakePHP Paginate Sort on Contain Data

It's a simple application for tracking user hobbies. A user can have many hobbies, which are organized into different hobby groups.
So I have 4 related tables: users, users_hobbies, hobbies, hobby_groups.
users is a has-and-belongs-to-many relation to hobbies, via the users_hobbies join table.
hobbies belongs-to a hobby_group, hobby_group has-many hobbies
Makes sense, pretty simple so far.
In UsersHobbiesController, I have:
$paginate = [
'contain' => [
'Hobby' => [
'fields' => ['id', 'name'],
'HobbyGroup' => [
'fields' => ['id', 'name']
]
]
]
];
Also, in my index() function, I build the pagination.
$usersHobbies = $this->paginate('UsersHobby');
$this->set(compact('usersHobbies));
When I access the $usersHobbies variable in my index.ctp View file, it has the data I want for building an output table. It looks like:
array(
(int) 0 => array(
'UsersHobby' => array(...),
'Hobby' => array(
'id' => 'abc-def-ghi',
'name' => 'Jet Skiing',
'HobbyGroup' => array(
'id' => 'oiuy-trew-qldf',
'name' => 'Watersports'
)
)
)
....
)
To sort the output table, I've added some sorting columns:
<th><?php echo $this->Paginator->sort('Hobby.name', 'Hobby'); ?></th>
<th><?php echo $this->Paginator->sort('Hobby.HobbyGroup.id', 'Hobby'); ?></th>
The first header works for sorting on the Hobby name. But I can't get the second header to sort for the HobbyGroup. Is there a simple way to do this?
I've searched for a few hours on StackOverflow, but can't seem to find an answer that works for me. Thanks.
This will not work as you expect because of how CakePHP fetches data.
Depending how you setup your relationships what will happen is that Cake will first select the Hobbies and then do another query for Hobby Groups.
So any sorting you apply to the second query will be generally useless and lost when that data is mapped to the list of Hobbies.
So you have
SELECT hobbies....
Then another select will be issued
SELECT hooby_groups WHERE hobby_id IN [list of ids ] ORDER BY hobby_groups_id
The data from the second select will be mapped to the first one, so your order by did not do much!
Depending on what CakePHP version you are using you can do a couple of things:
Define the relationship to use INNER JOIN strategy so will avoid creating two SELECT statements. This way the order by cause will sort all the data as you expect. The caveat is that with INNER JOIN Hobbies that do not have any group associated will never be selected by your pagination.
If you are using CakePHP 2.x you could have a look at Custom Query Pagination and build the query as you need it to be for it to work.
If you're using CakePHP 3.x you have a query builder there and the Paginator can paginate any query, so you can do you inner joins there.
To help you out you can use the DebugKit from CakePHP to see what actual queries are being run and how tweaking this and that parameter affects how the query is being generated. You will see where the order by is applied and why it may not work.
In CakePHP 2.x you can use type to control how the joining is done. You need to use INNER

Laravel - pivot relationship & naming the relationships

I have a table 'shop_visit_count' with columns ( 'user_id', 'shop_id', 'visit_count', 'created_at', 'updated_at' ),
A user can have many restaurant visit_counts, A restaurant can have many different user visit_counts of the same restaurant
the visit_count will be updated everytime the user visits a restaurant
Should I convert this to a pivot table?, or Should I add/keep the incremental Id primary key field?
If I need to convert to a pivot table, what should I name this many-to-many relationship? since this is not like the usual 'user', 'shop', 'shop_user' type relationship, but about the visit_count?
You can keep the table "shop_visit_count", it is ok. Pivot Tables don't bring much more.
Have you troubles with that actual table ?

Optimize query in Laravel Backpack n-n relationships

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.

Join two tables in Yii via relations

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',
...
...

Categories