Laravel Relationship between 3 tables - php

so I am trying to get the category name and this is what I have
tablets:
categories: id,name
post_categories: id, post_id, category_id
post : id, columns
I have the models: Post, PostCategory and Category.
Post Model :
public function categories()
{
return $this->hasMany('App\PostCategory');
}
PostCategory Model :
public function category()
{
return $this->hasMany(Category::class, 'id', 'category_id');
}
and in the controller I have
return Post::with('categories.category')->orderby('id','desc')->get();
And my result is
[
{
"id": 50,
"categories": [
{
"id": 92,
"category_id": 11,
"category": [
{
"id": 11,
"name": "JXrfLHdQVNON",
"image": null
}
]
}
]
}
]
and i wanted it to be something like
[
{
"id": 50,
"categories": [
{
"id": 1,
"name": "category_name",
"image": null
}
]
}
]
Is there a way to do it? I have been playing around with this and havent manage to find a easy way to do it

inside your Post model :
public function categories()
{
return $this->belongsToMany('App\Model\Category','post_categories','post_id','category_id')->withTimestamps();
}
in your controller :
return Post::with('categories:id,name,image')->orderBy('id','desc')->get();

This is a many-to-many relationship. Make sure you have your relationship set up correctly. If you want to choose specific columns you can do:
return Post::with('categories.category:id,name')->orderby('id','desc')->get();
It will return the columns id, name from category table/ model. You must specify id doing that.
https://laravel.com/docs/5.7/eloquent-relationships#many-to-many
https://laravel.com/docs/5.7/eloquent-relationships#eager-loading

Related

Laravel appends only one attribute from relationship

I'm trying to add an extra field to my Laravel 7 API model:
class Layer extends Model {
protected $fillable = ['name', 'filename', 'status', 'category_id'];
protected $appends = ['category_name'];
public function getCategoryNameAttribute()
{
return $this->category->name;
}
public function category()
{
return $this->belongsTo('App\LayerCategory', 'category_id');
}
}
My Controller:
.....
public function index()
{
return Layer::orderBy('name', 'asc')->paginate();
}
.....
I expect the following response:
{
"id": 1,
"category_id": 1,
"name": "My Layer",
"filename": "file_name.zip",
"status": true,
"category_name": "My category name"
}
But I receive:
{
"id": 1,
"category_id": 1,
"name": "My Layer",
"filename": "file_name.zip",
"status": true,
"category_name": "My category name",
"category": [
"id": 1,
"name": "My category name",
"status": true
]
}
How to return only the category name?
PS: I also tried with Resources.
Since you're eager loading the Category relationship to get category_name, you'll need to add logic to hide category from your JSON response. This can be done using the Hidden attribute on Serialization:
protected $hidden = ['category'];
You can read https://laravel.com/docs/7.x/eloquent-serialization#hiding-attributes-from-json for more information.

Laravel Eloquent Convert user_id to user info

I've some relationships in my Model classes.
Consume this relationship:
We've Post() model which store our posts data. Each post in this table has a user_id column that has one to many relationship with User() Mode (the author of the post)
class User extends Model {
public function posts()
{
return $this->hasMany('App\Post');
}
}
class Post extends Model {
public function user()
{
return $this->belongsTo('App\User');
}
}
So when i want to return my post with elequent, I'll get something like this:
{
"user_id": 1,
"title": "Foo name",
"body": "Foo body",
},
{
"user_id": 1,
"title": "Bar name",
"body": "another Bar body",
}
But i want to get something like this:
{
"user_id": 1,
"user": {
'name'=> 'John',
'last'=> 'Maco',
},
"title": "Foo name",
"body": "Foo body",
},
{
"user_id": 1,
"user": {
'name'=> 'John',
'last'=> 'Maco',
},
"title": "Bar name",
"body": "another Bar body",
}
You need to declare the relation from Post to User
Post.php
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
Then you will be able to load the user with every post like #dparoli commented
$post = Post::with('user')->get();

How to return a nested JSON format with given table structure using Laravel

If I have some table structure as below, how should I return the following JSON format using Eloquent ORM?
Table structure:
authors
id - integer
name - string
posts
id - integer
author_id - integer
title - string
images
id - integer
post_id - integer
filename - string
JSON format I expect to return:
[
{
"id": 1,
"name": "Jeffrey",
"posts": [
{
"id": 1,
"title": "Hello World",
"images": [
{
"id": 12,
"filename": "my-image.jpg"
},
{
"id": 13,
"filename": "your-image.jpg"
}
]
},
{
"id": 5,
"title": "Lorem Ipsum",
"images": [
{
"id": 20,
"filename": "his-image.jpg"
},
{
"id": 22,
"filename": "her-image.jpg"
}
]
}
]
}
]
Table structure: an author may have many posts, a post may have many images
JSON format: images are nested in post, posts are nested in author
Edited
Thanks for the reminder, I also added their Models:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Author extends Model
{
public function posts()
{
return $this->hasMany('App\Post');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function author()
{
return $this->belongsTo('App\Author');
}
public function images()
{
return $this->hasMany('App\Image');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
public function post()
{
return $this->belongsTo('App\Post');
}
}
If you add the relation Posts to your Author model and relation Images to your Posts model you will be able to make the request like this and it will take all of the data for you.
Author::with('posts.images')->get();

How to get records order by pivot column using laravel elquent?

I am trying to sort records order by highscore desc that I get top high scored users. I have tried a lot and still trying but could not achieve the task.
Following is working but it does sorting
$GameLog = User::with(['games' => function ($q){
$q->withPivot('highscore','level');
}])->get();
I also tried following to achieve it but this is also not working
$GameLog = User::with(['games' => function ($q){
$q->withPivot('highscore','level');
}])->groupBy(DB::raw('highscore DESC'))
->get();
I also tried sortBy() function in the loop but still I am facing issue. The first query is returning following result which should be sort by highscore
{
"status": "success",
"data": [
{
"id": 1,
"name": "fasdfsad",
"games": [
{
"id": 1,
"pivot": {
"highscore": 506,
}
}
]
},
{
"id": 8,
"name": "john",
"favorite_game_id": null,
"games": [
{
"id": 1,
"pivot": {
"highscore": 2340,
}
}
]
},
{
"id": 10,
"name": "tfyuyu",
"games": [
{
"id": 1,
"pivot": {
"highscore": 100,
}
}
]
}
]
}
Can someone kindly give me any idea how can I fix it I would appreciate. Thank you so much
Edited for Models
In Game.php
public function users()
{
return $this->belongsToMany(User::class, 'user_and_game', 'game_id', 'user_id')
->withPivot('highscore');
}
In User.php
public function games()
{
return $this->belongsToMany(Game::class, 'user_and_game', 'user_id', 'game_id');
}
I would like to appreciate if someone kindly help me about that
You need to create a new model for pivot (highscore). For example:
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class Highscore extends Pivot
{
public function user()
{
return $this->belongsTo(User::class);
}
public function game()
{
return $this->belongsTo(Game::class);
}
}
Note: from the example, we are extending from Pivot class instead of Model.
In the controller you can sort it like this example:
$highscores = Highscore::orderByDesc('score')
->with('user', 'game')
->get();
When using a custom pivot table, you need to define it from User and Games table.
public function users()
{
return $this->belongsToMany(User::class, 'user_and_game', 'game_id', 'user_id')
->using(Highscore::class)
->withPivot('highscore');
}

Laravel pass parameters from controller to Model using 'With' clause

I am new in Laravel,
I want to pass the the $id from my controller in the model using with clause
My model
class Menucategory extends Model
{
protected $fillable = ['title', 'parent_id', 'restaurant_id'];
// loads only direct children - 1 level
public function children()
{
return $this->hasMany('App\Menucategory', 'parent_id');
}
// recursive, loads all descendants
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}
}
My Controller
public function show($id)
{
$menucatagories = Menucategory::with('childrenRecursive')->where('restaurant_id',$id)->where('parent_id','0')->get();
return $menucatagories;
}
My current output is
[
{
"id": 1,
"title": "TestMenu Parant",
"parent_id": 0,
"restaurant_id": 12,
"children_recursive": [
{
"id": 2,
"title": "TestMenu SubCat1",
"parent_id": 1,
"restaurant_id": 12,
"children_recursive": [
{
"id": 6,
"title": "TestMenu other sub cat",
"parent_id": 2,
*******************
"restaurant_id": 13,
*******************
"children_recursive": []
},
{
"id": 7,
"title": "TestMenu other sub cat",
"parent_id": 2,
"restaurant_id": 12,
"children_recursive": []
}
]
},
{
"id": 3,
"title": "TestMenu SubCat2",
"parent_id": 1,
"restaurant_id": 12,
"children_recursive": []
}
]
}
]
I passed $id=12 , but the problem is I get the values of others restaurant_id in my child array, but if i use this it shows the correct jSON
public function childrenRecursive()
{
$id=12;
return $this->children()->with('childrenRecursive')->where('restaurant_id',$id);
}
my questions is how can i pass the $id from the controller to the model or is there any other approach?
You can pass your parameter in the controller itself using the following way.
public function show($id)
{
$menucatagories =Menucategory::with(array('childrenRecursive'=>function($query) use ($id){
$query->select()->where('restaurant_id',$id);
}))
->where('restaurant_id',$id)->where('parent_id','0')->get();
return $menucatagories;
}
Your childrenRecursive isn't wrong at all.
See here an simliar example: https://stackoverflow.com/a/18600698/2160816
So I think this should work
public function childrenRecursive($id = 12){
return $this->children()->where('restaurant_id',$id)->with('childrenRecursive');
}
Your Controller then could call
public function show($id)
{
$menucatagories = Menucategory::where('parent_id','0')->childrenRecursive(12)->get();
return $menucatagories;
}
I could not test it so may it won't work 100%

Categories