I have two tables named posts and categories. these two tables have one-to-many relationship and I wrote them in models like this:
class Post extends Model
{
...
public function category()
{
return $this->belongsTo(Category::class, 'category_id', 'id');
}
...
}
class Category extends Model
{
...
public function posts()
{
return $this->hasMany(Post::class, 'category_id', 'id');
}
...
}
This is work fine when I use $post = Post::find($id) in controller and retrieve one post and use $post->category to get category of this post. but what if I want to retrieve all posts and their categories together?
I mean, let's assume that I have 10 posts in DataBase and I have $posts = Post::get(); to get all posts. now, how I can get categories of each post?
One way is loop! for example:
foreach($posts as $post) {
$post['category'] = $post->category;
}
return response()->json($posts);
Yeah! I want to response in Json and I forgot to say earlier, sorry.
Is there better way to do this? I searched and I got nothing by my search. I'll be appreciated if anyone response to my problem. :)
The easiest way to include categories in each post model with json, is simply including it using with() and it will automatically transform it.
return Post::with('category')->get();
In Laravel you do not have to wrap models or collections in response->json(); it will automatically do that.
Related
To keep things simple, I'll give an example in code to what I'm trying to Achieve.
Let's assume that we have a model called User with the following code:
class User
{
public function posts()
{
return $this->hasOne(Post::class);
}
}
And the Post model look something like this.
class Post
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
And now what I want to be able to do is for example:
$user = Auth::user();
$comments = $user->post->comments; //here, I only want the "comment_id" and "comment_content" fields to be included, not all the Comment Model fields !
you can simply use hasManyThrough in user model to connect comments table.
read about hasManyThrough here: docs
and after having a relation between user and comments (hasManyThrough)
you can use load (Lazy eager loading) method
there is an piece of code you can use here
$user->load(["comments" => function($q){
$q->select("comment_id","comment_content");
}]);
read more about Lazy eager loading: docs
I have 2 Models: Post and Image. Each Image is associated with a Post and one Post can have many Images, as its shown below.
public function post()
{
return $this->belongsTo(Post::class, 'id', 'post_id');
}
public function images()
{
return $this->hasMany(Image::class, 'post_id', 'id');
}
But, When I try to retrieve Post with a id:1 it using:
$post = Post::find($id);
$post->images;
It brings me ALL posts, not the specific one, as you can see below:
However, when I return using this syntax:
$post->with(['images'])->where('id', $post->id)->get();
it works fine, but the first method should work as well, shouldn't it?
if you want to get one post by post_id and all images belong to it you can try it:
$post = Post::with(['images'])->findOrFail($id);
I have a has many relation between models: post and category in laravel application. I've defined these relations as:
public function category() {
return $this->belongsTo('artSite\category');
}
public function posts() {
return $this->hasMany('artSite\post');
}
Now I'm trying retrieve posts belonging to the particular category which are derived in http request:
Route::get('posts/categories/{categoryName}','postsViewController#showPostGivenCategory')
Below I show my controller function (it does work fine!):
public function showPostGivenCategory($categoryName) {
$category = category::where('category_name','=',$categoryName)-first();
$posts = category::find($category->id)->posts;
return view('pages.homePage')->with('categories',$categories)with('posts',$posts);
}
In this solution I'm creating 2 queries. Is any possible way to create 1 query to retrieve posts of particular category in has many relation?
Something like that doesn't work:
$posts = category::where('category_name','=',$categoryName)->posts;
Could someone help me with this problem? I would be very grateful, greetings.
we can get rid of the second line :
$posts = Category::find($category->id)->posts;
So You can say :
$posts = Category::where('category_name','=',$categoryName)->first()->posts;
Is it possible to make a multi level relation query with Eloquent on a deeper level than 1 level? My tables look like this :
post_comments-> id|comment|post_id|user_id|...
post_comment_replies-> id|reply|post_comment_id|user_id|...
users-> id|name|....
user_data-> id|avatar|...
And so I want to ask is it possible to get the Comments for a Post with all the Replies and the User Data for the person who replied to a comment in 1 query with Eloquent.
This is how my Comments Model looks like:
class PostComment extends Model{
public function replies(){
return $this->hasMany(PostCommentAwnsers::class);
}
public function user() {
return $this->belongsTo(User::class);
}
public function userInfo(){
return $this->belongsTo(UserInfo::class,'user_id','user_id');
}}
public function index($id){
$posts = Post::find($id);
$postComments = PostComment::where('post_id','=',$id)->paginate(5);
return view('post.show',[
'post' => $post,
'postComments' =>$postComments
]);
}
And as I get all the user data for a Comment I want to get all the user data for the person who replied.
I am really sorry if this has been awnsered or documented somewhere else but I just can't seem to find the exact solution to this problem.
You should look for eager loading : https://laravel.com/docs/5.3/eloquent-relationships#eager-loading
if you want to get all posts and their comments :
$posts = Post::with('comment')->get();
and if you want all posts with comments and replies of the comments :
$posts = Post::with('comment.reply')->get();
Suppose I have a User model and a Post model.
class Post extends Eloquent
{
}
There are many users, and each User has many Post. All Post belongs to a User.
class User extends Eloquent
{
public function posts()
{
return $this->hasMany('Post');
}
}
I know that I can get a single User with find().
$user = User::find(1);
I know that from a single User, I can get all their posts().
$posts = User::find(1)->posts;
However, suppose now I have multiple users.
$users = User::all();
I wish to access all the posts that this collection of users have. Something along the lines of
$posts = User::all()->posts;
This, of course, doesn't work. However, in theory, it should be functionally equivalent to
$posts = Post::all()
Is there a way to do something similar to the above in Laravel 4.2?
I do not want to use Post::all(). Reason being that it would not be what I want in a more complicated example that involves constraints on User.
$postsByMaleUsers = User::where('gender', '=', 'male')->posts;
Should get all the posts made by male users.
I am also aware that I could simply use a foreach loop.
foreach($users->posts as $post)
{
// Process result here.
}
However, suppose I am trying to return the results instead of processing the results. For example, I could have a public static function postsByMaleUsers() in the User model, and calling User::postsByMaleUsers() should return a collection of posts by male users only. In which case, the foreach loop would not suit me.
Eager load the posts, then use pluck and collapse to get a flat collection of posts:
$users = User::with('posts')->where('gender', 'male')->get();
$posts = $users->pluck('posts')->collapse();