count comments associated with post - laravel

I have two comments associated with a post, but the code to count the comments associated with the posts shows "1". Do you know why?
code to count the comments:
$commentsCount= Post::with('comments')->count();
A post can have multiple comments, a comment is associated with a post.
Comment model:
public function post(){
return $this->belongsTo('App\Post');
}
Post model:
public function comments(){
return $this->hasMany('App\Comment', 'post_id');
}
Do you know why?

Calling with will eager load the comments onto the Post model but still only return one Post object.
You need to call comments on a post object to get a collection back that you can count.
Judging by the code you have if you do something along the lines of
$post = Post::find(1);
$commentsCount = $post->comments->count();
You should get what you are looking for.

Related

Limiting to a single many-to-many relationship in Laravel eloquent

A Paper can have many Authors and an Author can have many Papers. An Author cannot be listed as an Author more than once on the same Paper.
I've set up the many-to-many relationship in Laravel and I am able to use the attach method to link Authors to a Paper. However, Laravel allows me to add the same Author twice.
Here is a contrived example.
// App\Models\Author
public function papers() {
return $this->belongsToMany (Paper::class);
}
// App\Models\Paper
public function authors() {
return $this->belongsToMany (Author::class);
}
// LinkController
public function store (Author $author) {
$author->papers()->attach (request ("paper")); // works
$author->papers()->attach (request ("paper")); // adds a second link, should do nothing.
}
Obviously I'm hard-coding the second attach above, but users can select the same author twice.
How can I tell Laravel to silently ignore the second request?
I've discovered the syncWithoutDetaching method:
// LinkController
public function store (Author $author) {
$author->papers()->syncWithoutDetaching ([request ("paper")]);
$author->papers()->syncWithoutDetaching ([request ("paper")]); // does nothing.
}

Laravel eloquent query with sum of related table

I have a table users and posts with columns user_id and post_views.
In post_views I keep information how many times post was display.
And now, in query I would like to get user with sum of post_views all his posts.
I tried do something like this:
User::where(['id'=>$id])->with('posts')->get();
And in model I defined:
public function posts()
{
return $this->hasMany('App\Models\Post')->sum('post_views','AS','totalViews');
}
But without success.
How to do it?
Thank you
You can use a modified withCount():
public function posts()
{
return $this->hasMany('App\Models\Post');
}
$user = User::withCount(['posts as post_views' => function($query) {
$query->select(DB::raw('sum(post_views)'));
}])->find($id);
// $user->post_views
You can use
User::withCount('posts')->find($id)
to get the user with the id $id and a posts_count attribute in the response
I'm not fully sure what the intention of ->sum('game_plays','AS','totalVies'); is - you would need to add more context if you want this
Just something to add with regards to your shown code: No need to query by id using where + the get() at the end will make you query for a collection. If you want to get a single result use find when searching by id
As always laravel has a method for that : withSum (Since Laravel v8)
Note : I know that at the time of the message was posted, the method did not exist, but since I came across this page when I was looking for the same result, I though it might be interesting to share.
https://laravel.com/docs/9.x/eloquent-relationships#other-aggregate-functions
In your case it should be :
$user = User::withSum('posts as total_views', 'post_views')->find($id);
Then you can access to the result :
$user->total_views

How to load Laravel with nested models and limit the nested models?

Hello guys I am using Laravel 5.6 I have three tables in the database posts,comments and replies and three models Post , Comment , Reply
the relations are as follow one post has many comments and one comment has many replies. I created a route that when hit will return some data ;however, I want this data to be in a specific way read this example:
Lets say I have 6 posts in my database and each post has 6 comments also each comment has 6 replies I want to return only the first 3 posts along with the first 3 comments for each post also the first 3 replies for each comment
//this is a function inside a controller
//and for sure I have make sure to make use of the models namespaces
public function test(){
$posts = Post::with(['comments' => function($data){
return $data->take(3);
},
'comments.replies' => function($data){
return $data->take(3);
}])->paginate(3);
//returning the posts
return $posts
}
This way is working it returns the first 3 post and it returns the first 3 comments and first 3 replies only for the first post but for other posts I only get an empty key of comments so there is no replies as a result
hope you get my question please help
sorry for big question
Thanks in advance.
There is no native support for this in Laravel.
I created a package for it: https://github.com/staudenmeir/eloquent-eager-limit
Use the HasEagerLimit trait in both the parent and the related model.
class Post extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
class Comment extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
Then you can apply ->take(3) to your relationship.
The same goes for the replies.

Laravel retrieving single related attribute

I have a laravel app that allows users to post posts. Each post has a price (stored as an integer), and belongs to a university, which in turn belongs to a country, which has a currency.
Every-time I retrieve the posts, I want to return the currency as well. I could do with('university.country') but that would return all the details for both the university and country.
I could add a getCurrencyAttribute and define the logic there, but that seems not what mutators are for, especially since if I get all the posts, each post will further run two of its own queries just to get the currency. That's 3 queries to get one post, which quickly takes its toll when returning more than 10 posts.
public function getCurrencyAttribute() {
return $this->university->country->currency;
}
public function getPriceAttribute($value) {
return "{$this->currency}{$value}";
}
^ example above: no need for appends because price is automatically overwritten. This is the problem as seen on DebugBar (two new queries are being called on the Post model, which while expected, becomes inefficient when retrieving lots of posts):
What's the best way to get a single related field, every-time?
Full code on GitHub.
You can limit the eager loading columns:
Post::with('webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency')->get();
If you always need it, add this to your Post model:
protected $appends = ['currency'];
protected $with = ['webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency'];
public function getCurrencyAttribute() {
return $this->webometricUniversity->country->currency;
}
Then you can just use Post::get() and $post->currency.

Laravel Eloquent one-to-many relationships

I have post table and comments table. I want to get all posts with its comments and the following returns just post which has comments:
Post::with('comments')
UPDATE
for example
post_table
id post
1 post1
2 post2
comment table
id post_id comment
1 1 sapmle_comment
Post::with('comments') returns only that posts, which have comments, it returns only first post, becouse second post doesnot have comments, i want to get all post (with or without comments)
Your question is not clear enough but to get all the posts with comments you may try this:
$posts = Post::with('comments')->get();
To get posts only which has comments you may try this:
$posts = Post::has('comments')->get();
I'm not too sure what your question is, but I am assuming that it is not returning your comments. If your not able to return posts that do not have comments Sheikh's answer will work for you. If you are not able to retrieve the comments for each post you should make sure your model has defined:
public function comments(){
return $this->hasMany('Comment');
}
and then make sure your comments model has:
public function post(){
return $this->belongsTo('Post');
}
If you want to pass this along to your view from the controller you can:
$comments = $post->comments()->orderBy('created_at')->get();
return View::make('view', compact('comments'));
You can loop through each of the comments by:
#foreach ($comments as $comment)
{{$commment->content}}
#endforeach

Resources