Laravel many to many with 3 models - php

I've been struggling with a issue the last couple of days. I've just started using Laravel and are getting real fond of the Eloquent-syntax!
But there's a issue when I'm trying to get the correct relation between three models.
I've got this setup:
programs table contains
event_id
user_id
role_id
In my Event-model I've got
public function programs(){
return $this->hasMany(Program::class);
}
In my User-model I've got
public function programs(){
return $this->hasMany(Program::class);
}
In my Role-model I've got
public function programs(){
return $this->hasMany(Program::class);
}
And my Program-model contains
public function event(){
return $this->belongsTo(Event::class);
}
public function user(){
return $this->belongsTo(User::class);
}
public function role(){
return $this->belongsTo(Role::class);
}
And I need to get the following result
Events -> Users -> Role
In my controller I've got
$events = Event::with('programs.role.programs.user')->get();
Which is producing this:
{
"id": 2,
"name": "Concert: Freddy Kalas",
"description": "Freddy Kalas konsert",
"user_id": 2,
"time_from": "12.04.2017 22:00:00",
"time_to": "12.04.2017 23:00:00",
"created_at": "2017-03-20 18:28:44",
"updated_at": "2017-03-20 18:28:44",
"programs": [
{
"id": 2,
"event_id": 2,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"role": {
"id": 1,
"name": "Camera operator",
"description": "Operates ordinary cameras or PTZ cameras",
"created_at": "2017-03-20 20:11:06",
"updated_at": "2017-03-20 20:11:06",
"programs": [
{
"id": 1,
"event_id": 3,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"user": {
"id": 2,
"name": "Dummy Dum",
"email": "dummy#example.com",
"created_at": "2017-03-20 16:45:09",
"updated_at": "2017-03-20 16:45:09"
}
},
{
"id": 2,
"event_id": 2,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"user": {
"id": 2,
"name": "Dummy Dum",
"email": "dummy#example.com",
"created_at": "2017-03-20 16:45:09",
"updated_at": "2017-03-20 16:45:09"
}
}
]
}
}
]
},
{
"id": 3,
"name": "Prøveproduksjon",
"description": "Prøveproduksjon med video og lyd",
"user_id": 1,
"time_from": "11.04.2017 13:00:00",
"time_to": "11.04.2017 17:00:00",
"created_at": "2017-04-03 17:12:37",
"updated_at": "2017-04-03 17:12:37",
"programs": [
{
"id": 1,
"event_id": 3,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"role": {
"id": 1,
"name": "Camera operator",
"description": "Operates ordinary cameras or PTZ cameras",
"created_at": "2017-03-20 20:11:06",
"updated_at": "2017-03-20 20:11:06",
"programs": [
{
"id": 1,
"event_id": 3,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"user": {
"id": 2,
"name": "Dummy Dum",
"email": "dummy#example.com",
"created_at": "2017-03-20 16:45:09",
"updated_at": "2017-03-20 16:45:09"
}
},
{
"id": 2,
"event_id": 2,
"user_id": 2,
"role_id": 1,
"created_at": null,
"updated_at": null,
"user": {
"id": 2,
"name": "Dummy Dum",
"email": "dummy#example.com",
"created_at": "2017-03-20 16:45:09",
"updated_at": "2017-03-20 16:45:09"
}
}
]
}
}
]
}
I can't get the models to relate to eachother - it seems. The preferred result that I want is that all the Events is tied with many users - and all the users for that event to be tied to one role. How can i accomplish this with Laravel and Eloquent?
Thanks for any responses!
EDIT:
To fetch the data i use the following code to generate the results above
$events = Event::with('programs.role.programs.user')->get();
Content of the programs table
# id, event_id, user_id, role_id, created_at, updated_at
'1', '3', '2', '1', NULL, NULL
'2', '2', '2', '1', NULL, NULL
This would mean that the user with an ID of 2 is only associated with event 3 with an role of 1 and event 2 with a role of 1. As you can see from the results both events has both role 1 and 2. Sorry for bad explanation..

Probably just try to make it one at a time and figure out what is returned.
#Fredrik Angell Moe said:
Got it working now by using:
$events = Event::with('programs.role')->with('programs.user')->get();

user with an ID of 2 is only associated with event 3 with an role of 1
and event 2 with a role of 1. As you can see from the results both
events has both role 1 and 2.
You are using two values. One is id of user and second is id of event.
Laravel can define realtion between only two models. That means in you query you are using the programe_id and event_id.
But user_id is getting neglected. So it will just add the user related to the model instead of filtering with the user_id.
The best way to solve this problem is instead of using the relation go for the raw query where you need to get relation between more than two models.

Related

Laravel paginate(10) not working for second page

I am trying Laravel's paginate function but the URL below returns the same records every time. This means that it's showing only the first 10 records no matter which page we're on. I don't know why.
URL - https://example.com/api/getWebGalleryImages?page=3
My Controller function
public function getWebGalleryImages() {
$galleryFIle = WebGallery::orderBy('id', 'desc')->paginate(10);
return response()->json($galleryFIle, 200);
}
My route
Route::get('getWebGalleryImages', 'FrontController#getWebGalleryImages');
Every time same response
{
"current_page": 1,
"data": [
{
"id": 11,
"file_name": "1627985668_download(2).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 10,
"file_name": "1627985646_istockphoto-1093301674-612x612.jpg",
"created_at": null,
"updated_at": null
},
{
"id": 9,
"file_name": "1627985646_images(4).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 8,
"file_name": "1627985646_images(3).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 7,
"file_name": "1627985645_images(2).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 6,
"file_name": "1627985645_images(1).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 5,
"file_name": "1627985645_download(2).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 4,
"file_name": "1627985645_download(1).jpg",
"created_at": null,
"updated_at": null
},
{
"id": 3,
"file_name": "1627985644_Diamond.jpg",
"created_at": null,
"updated_at": null
},
{
"id": 2,
"file_name": "1627985644_depositphotos_3929711-stock-photo-diamond-on-black-background.jpg",
"created_at": null,
"updated_at": null
}
],
"first_page_url": "https://example.com/api/getWebGalleryImages?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "https://example.com/api/getWebGalleryImages?page=2",
"next_page_url": "https://example.com/api/getWebGalleryImages?page=2",
"path": "https://example.com/api/getWebGalleryImages",
"per_page": 10,
"prev_page_url": null,
"to": 10,
"total": 11
}
From the Response in your Question, your query seems to have 11 matched records and the your Result Per Page is set to 10 meaning you only have 2 pages of records. so calling page=3 in your query is not going to get you a new record as that page is unavailable.
If you need the pagination to work set your Result Per Page to a lower value, let say 3 or add more data to the records.

Getting Duplicate Data on Response On Laravel Eloquent

I am new in laravel in php. So it might be very silly mistake. I have song table and song categories table. I am trying to fetch all category with their respective songs. I have implemented larvel eloquent one to many relationship between song category and song.
Here is my code of fetching data:
public function getSongCategoriesWithSongs(){
$json_array = array();
$song_categories = SongCategory::all();
foreach ($song_categories as $item) {
# code...
$json = [];
$json['category'] = $item;
$json['songs'] = $item->songs;
array_push($json_array,$json);
}
return $json_array;
}
Here is response:
[{
"category": {
"id": 1,
"title": "Rock",
"created_at": "2020-12-20T02:58:32.000000Z",
"updated_at": "2020-12-20T02:58:32.000000Z",
"songs": [{
"id": 1,
"title": "Mere Mehboob",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/2u039f-a.akamaihd.net\/downloads\/ringtones\/files\/mp3\/mere-mehboob-qayamat-hogi-52150.mp3",
"created_at": "2020-12-20T13:26:30.000000Z",
"updated_at": "2020-12-20T13:26:30.000000Z"
}, {
"id": 2,
"title": " Taaron Ke Shehar",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/newmp3ringtones.net\/assets\/sass\/Ringtones\/TaaronKeSheharRingtoneByNehaKakkarJubinNautiyal2145436126.mp3",
"created_at": null,
"updated_at": null
}, {
"id": 3,
"title": "Bewafa Tera Masoom Chehra",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/newmp3ringtones.net\/assets\/sass\/Ringtones\/BewafaTeraMasoomChehraRingtoneByJubinNautiyal352778308.mp3",
"created_at": null,
"updated_at": null
}]
}
}, {
"songs": [{
"id": 1,
"title": "Mere Mehboob",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/2u039f-a.akamaihd.net\/downloads\/ringtones\/files\/mp3\/mere-mehboob-qayamat-hogi-52150.mp3",
"created_at": "2020-12-20T13:26:30.000000Z",
"updated_at": "2020-12-20T13:26:30.000000Z"
}, {
"id": 2,
"title": " Taaron Ke Shehar",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/newmp3ringtones.net\/assets\/sass\/Ringtones\/TaaronKeSheharRingtoneByNehaKakkarJubinNautiyal2145436126.mp3",
"created_at": null,
"updated_at": null
}, {
"id": 3,
"title": "Bewafa Tera Masoom Chehra",
"thumbnail": "https:\/\/static.toiimg.com\/photo\/msid-71407401\/71407401.jpg?108311",
"song_category_id": 1,
"stream_link": "https:\/\/newmp3ringtones.net\/assets\/sass\/Ringtones\/BewafaTeraMasoomChehraRingtoneByJubinNautiyal352778308.mp3",
"created_at": null,
"updated_at": null
}]
}, {
"category": {
"id": 2,
"title": "Soft",
"created_at": null,
"updated_at": null,
"songs": []
}
}, {
"songs": []
}]
As you can see songs get repeated.
UPDATE
Solved using eager loading
public function getSongCategoriesWithSongs(){
return SongCategory::with('songs')->get();
}
But don't know why the foreach method not working.
Try this code
public function getSongCategoriesWithSongs(){
$json_array = array();
$song_categories = SongCategory::all();
foreach ($song_categories as $item) {
$json_array[] = ['category' => $item, 'songs' => $item->songs] ;
}
return $json_array;
}
The problem is that you assign the same relation twice.
Each SongCategory already has a collection of songs inside.
So in your foreach block, you assign a category with $json['category'] => $item which will load all related songs and pass them to the final JSON object. And you duplicate this by passing the next item $json['songs'] = $item->songs to the same array. Default Laravel behavior will be to fetch all related objects and transform them into JSON.
I would suggest you to use Laravel resources to return JSON objects with exact shapes: API Resources.
You can fix your code block without eager loading by removing $json['songs'] = $item->songs assignment.
Eager loading works because you passed all your objects only once.

Laravel/Lumen: Handling the fetchresults of Model::With('Relation')

I have three related tables:
Table Coretable which is referenced by Table extensiontable_itc and extensiontable_sysops.
I now want to get all the records from coretable which are referenced by extensiontable_itc and extensiontable_sysops, and to do so, I run this code:
$join = coretable::with('extensiontable_itc','extensiontable_sysops')->get();
and this kind of works, I get the following result:
[{
"id": 1,
"Internal_key": "TESTKEY_1",
"created_at": null,
"updated_at": null,
"extensiontable_itc": {
"id": 1,
"coretable_id": 1,
"description": "EXTENSION_iTC_1",
"created_at": null,
"updated_at": null
},
"extensiontable_sysops": {
"ID": 1,
"coretable_id": 1,
"description": "EXTENSION_SYSOPS_1"
}
}, {
"id": 2,
"Internal_key": "TESTKEY_2",
"created_at": null,
"updated_at": null,
"extensiontable_itc": {
"id": 4,
"coretable_id": 2,
"description": "EXTENSION_ITC_2",
"created_at": null,
"updated_at": null
},
"extensiontable_sysops": {
"ID": 2,
"coretable_id": 2,
"description": "EXTENSION_SYSOPS_2"
}
}, {
"id": 3,
"Internal_key": "TESTKEY_3",
"created_at": null,
"updated_at": null,
"extensiontable_itc": {
"id": 5,
"coretable_id": 3,
"description": "EXTENSION_ITC_3",
"created_at": null,
"updated_at": null
},
"extensiontable_sysops": {
"ID": 3,
"coretable_id": 3,
"description": "EXTENSION_SYSOPS_3"
}
}, {
"id": 4,
"Internal_key": "TESTKEY_4",
"created_at": null,
"updated_at": null,
"extensiontable_itc": {
"id": 6,
"coretable_id": 4,
"description": "EXTENSION_ITC_4",
"created_at": null,
"updated_at": null
},
"extensiontable_sysops": {
"ID": 4,
"coretable_id": 4,
"description": "EXTENSION_SYSOPS_4"
}
}, {
"id": 5,
"Internal_key": "TESTKEY_5",
"created_at": null,
"updated_at": null,
"extensiontable_itc": {
"id": 7,
"coretable_id": 5,
"description": "EXTENSION_ITC_5",
"created_at": null,
"updated_at": null
},
"extensiontable_sysops": {
"ID": 5,
"coretable_id": 5,
"description": "EXTENSION_SYSOPS_5"
}
}]
As you can see, the records referencing the respective record on coretable are put into an array, which itself becomes an element of the overall array containing the data from coretable.
Now, I want to get ALL this data EXCEPT for:
The ids from coretable
The created_at/updated_at
the foreign keys/coretable_ids
I already worked with the collection method "pluck()", but it doesn't seem to fit the purpose of accessing this multi-level array with all these duplicates in the indexes.
Is there any convenient way to do this? Or do I have to do it manually, using loops?
https://laravel.com/docs/5.8/eloquent-serialization#hiding-attributes-from-json
There are two ways to hide fields. The first one is to put needed fields to $hidden array inside model class, and all these fields will not be included in the model instance. The second one is to use makehidden function. This allows you to hide fields dynamically, depend on some conditions as an example.

How to modify array structure returned by eloquent in laravel

I currently have the below array structure that I get when running Bonus::with('users')->get()
I have tried adding the array and merging similar keys but it is not working. I tried using the helper methods provided in laravel but I don't seem to be able to get it working.
[
{
"id": 1,
"users_id": 1,
"bonus_type_id": 1,
"is_paid": 0,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "test",
"email": "test#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
},
{
"id": 2,
"users_id": 1,
"bonus_type_id": 2,
"is_paid": 0,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "test",
"email": "test#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
},
{
"id": 3,
"users_id": 2,
"bonus_type_id": 2,
"is_paid": 1,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "another test",
"email": "another#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
}
]
I want the result to be something like that
[
{
user_id: 1,
name: "test",
bonuses: [
{
bonus_type_id: 1,
amount: 100,
is_paid: 0,
},
{
bonus_type_id: 2,
amount: 100,
is_paid: 0,
}
],
},
{
user_id: 2,
name: "another",
bonuses: [
{
bonus_type_id: 2,
amount: 100,
is_paid: 1,
},
]
}
]
You need to change your eloquent relationship. Define hasMany relationship function bonuses inside User model for bonuses table and use that to get the desired result like so:
User::with('bonuses')->get();
That way it will return results from users table and populate bonuses for each user.
makes sense?
You can get specific information with select subquery, if your relations are correctly set, this should work.
User::select('user_id','name','bonus_id')
->with(array('bonuses'=> function($query){
$query->select('bonus_type_id','amount','is_paid');
}))->get();

Laravel 5.2: extracting nested collection

I am working on Laravel 5.2 application. I'm having an issue in extracting the nested collection from the parent collection. I'm trying to get all the posts from the users whom I am following like this:
$posts = \Auth::user()->following()->get()->each(function($following){
return $following->posts;
});
But it is returning me a collection of the users I am following and the posts collection is nested in this collection, such that:
[
{
"id": 2,
"name": "John Doe",
"username": "john",
"email": "johny#example.com",
"created_at": "2016-03-08 11:06:45",
"updated_at": "2016-03-08 11:06:45",
"pivot": {
"follower_id": 1,
"followee_id": 2
},
"posts": [
{
"id": 1,
"user_id": 2,
"title": "Post title 1",
"created_at": "2016-03-08 11:09:22",
"updated_at": "2016-03-08 11:09:22"
},
{
"id": 3,
"user_id": 2,
"title": "Post title 2",
"created_at": "2016-03-09 08:04:18",
"updated_at": "2016-03-09 08:04:18"
}
]
}
]
How can I get all the posts from the all of the users I'm following as a collection?
Any help will be appreciated
$posts = [];
\Auth::user()->following()->get()->each(function($following) use(&$posts){
array_push($posts, $following->posts)
});
Hope this helps.

Categories