Laravel hasMany relation count number of likes and comments on post - php

The code:
$posts = Jumpsite::find($jid)
->posts()
->with('comments')
->with('likes')
->with('number_of_comments')
->with('number_of_likes')
->where('reply_to', 0)
->orderBy('pid', 'DESC')
->paginate(10);
Each post has a comment and likes. I only display a few of the comments initially to avoid large loads. But I want to show how many the total comments and likes for each post. How do I do this?
Model code:
public function likes()
{
return $this->hasMany('Like', 'pid', 'pid');
}
public function comments()
{
return $this->hasMany('Post', 'reply_to', 'pid')->with('likes')->take(4);
}
public function number_of_likes()
{
return $this->hasMany('Like', 'pid', 'pid')->count();
}
Note:
This is an API. All will be returned as JSON.
update
The return
Post
author_id
message
Comments(recent 4)
user_id
message
post_date
Number_of_likes
Likes
user_id
Number_of_total_comments
Number_of_total_likes
update
How I return the data
$posts = $posts->toArray();
$posts = $posts['data'];
return Response::json(array(
'data' => $posts
));
Just by using that I get all the data i want in the json. But I also want to add the total counts.
update
protected $appends = array('total_likes');
public function getTotalLikesAttribute()
{
return $this->hasMany('Like')->whereUserId($this->uid)->wherePostId($this->pid)->count();
}
but getting the error:
Unknown column 'likes.post_id'
error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'likes.post_id' in 'where clause' (SQL: select count(*) as aggregate from `likes` where `likes`.`deleted_at` is null and `likes`.`post_id` = 4 and `pid` = 4 and `uid` = 1)

You can use that following code for counting relation model result.
$posts = App\Post::withCount('comments')->get(); foreach ($posts as $post) { echo $post->comments_count; }
And also set condition with count like this
$posts = Post::withCount(['votes', 'comments' => function ($query) { $query->where('content', 'like', 'foo%'); }])->get();

In your model place the following accessors:
Count total Likes:
public function getTotalLikesAttribute()
{
return $this->hasMany('Like')->whereUserId($this->author_id)->count();
}
Count total comments:
From your description, i can see, you have retrieving the number of posts as comments
public function getTotalCommentsAttribute()
{
return $this->hasMany('Post')->whereUserId($this->author_id)->count();
}
Now, from your controller:
$post = Jumpsite::find($jid);
// total comments
var_dump( $post->total_comments );
// total Likes
var_dump( $post->total_likes );

Count comments for all blog posts in laravel
Step 1: Place this code inside your ‘Post’ model.
// Get the comments for the blog post.
public function comments()
{
return $this->hasMany('App\Comment');
}
Step 2: Place this code inside your ‘PostController’ controller.
$posts= Post::all();
return view('home')->with('posts', $posts);
Step 3: Then count comments for all posts using the below code.
#foreach($posts as $row)
{{$row->comments->count()}}
#endforeach
See details here: http://www.pranms.com/count-comments-for-all-blog-posts-in-laravel/

Just single change to get results of the count
In relation
public function getTotalLikesAttribute(){
return $this->hasMany('Like')->where('author_id',$this->author_id)->count();
}
In the view
$post->getTotalLikesAttribute()

Related

Take last 3 records from child. Php/Laravel

Help me please.
I'm trying to write a function where I get all the categories of my forum with the 3 most recently updated Topics in the given categories.
But according to the result, take(3) filters by id (where the id is not higher than 3), and I need to get the last 3 records.
public function index()
{
$forums = Category::with(['posts' => function ($q){
return $q->take(3)->get();
}])->get();
dd($forums);
}
you should order your complete query by update_at descending, only after you can take the first 3.
$q->orderBy('update_at', 'desc')->take(3)->get();
Your Categories table seems to be a different table from posts, so when a post is created or updated you should also set update_at of its category to now.
As far as I know you can not use take() or limit() inside with();
EDIT: solution that was selected by mr.Sardov is to use package staudenmeir/eloquent-eager-limit.
Link is provided below this answer.
So for you need to do is by limit it from model relationship.
For example:
class Category extends Model {
public function posts()
{
return $this->hasMany('App\Models\Post');
}
public function limitPosts()
{
return $this->hasMany('App\Models\Post')
->limit(3);
}
public function limitLatestPosts()
{
return $this->hasMany('App\Models\Post')
->orderBy('created_at', 'desc'). // or use ->latest()
->limit(3);
}
}
And that use it like this:
Category::query()
->with(['limitPosts' => function($query) {
$query->orderBy('created_at', 'desc'); // the last records
}])
->where('id', '<=', 3) // id not higher than 3
->get();
Or
Category::query()
->with('limitLatestPosts')
->where('id', '<=', 3) // id not higher than 3
->get();
Hope this can help you out.

Display Posts by Category in Laravel 8

i have some issues that happen with my code for displaying posts by category..
Relation is one to many, post to category.. I can route to choosen category, but posts did not show..
Here's my Post Model:
public function category()
{
return $this->belongsTo(CategoriesPost::class);
}
Category Model:
public function posts()
{
return $this->hasMany(Post::class, 'category_id');
}
And here's my PostController
$posts = Post::where('article_status', 'published')->whereHas('category', function ($query) use ($slug) {
return $query->where('category_slug', $slug);
});
$category = CategoriesPost::where('category_slug', $slug)->first();
return view('pages.article', [
'posts' => $posts,
'category' => $category,
]);
I'm so sure my code was right, but why it didn't shows the posts, did anyone notice where's the problem of my code?
Rather than querying for the related Posts separately, why not access them via the relationship you have defined in your Category model? It will improve performance by reducing the number of calls to your database for a start.
So something like:
$category = CategoriesPost::with(['posts'])->where('category_slug', $slug)->first();
Then you can just access your posts relationship on the $category property in your view:
$category->posts;

Laravel paginate pivot tables

I have collections which contains custom products I need to paginate those collections products but I receive error.
data
With this query I can get my collection and it's products but I'm not able to paginate products.
$collection = Collection::where('slug', $slug)->where('status',
'active')->with('products')->first();
With this query I receive error
$collection = Product::with('collections')->whereHas('collections',
function($query) use($slug) { $query->where('slug',
$slug)->where('status', 'active')->first(); });
Error
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'shopping.product_id' doesn't exist (SQL: select * from `collection_products` inner join `product_id` on `collection_products`.`id` = `product_id`.`collection_product_id` where `products`.`id` = `product_id`.`product_id` and `slug` = test and `status` = active limit 1)
Code
Product model
public function collections()
{
return $this->belongsToMany(CollectionProduct::class, 'product_id');
}
Collection model
public function collection(){
return $this->belongsToMany(CollectionProduct::class);
}
public function products(){
return $this->belongsToMany(Product::class, 'collection_products', 'collection_id', 'product_id');
}
CollectionProduct model
public function collection()
{
return $this->belongsTo(Collection::class, 'collection_id','id');
}
Controller default query
public function single($slug){
$collection = Collection::where('slug', $slug)->where('status', 'active')->with('products')->first();
return view('front.collections.single', compact('collection'));
}
Question
How can I get my collection products with pagination ability?
Couple things:
You are trying to call the first() method inside of a relationship query in this line:
$collection = Product::with('collections')->whereHas('collections', function($query) use($slug) { $query->where('slug', $slug)->where('status', 'active')->first(); });
The methods first() and get() are used to execute the query, so you should keep them at the end of the chain of eloquent methods:
$collection = Product::with('collections')
->whereHas('collections', function($query) use($slug) {
$query->where('slug', $slug)->where('status', 'active');
})
->get();
https://laravel.com/docs/5.7/eloquent#retrieving-models
However, if you want to paginate the list of products, then what you really want is the paginate() method:
$collection = Product::with('collections')
->whereHas('collections', function($query) use($slug) {
$query->where('slug', $slug)->where('status', 'active');
})
->paginate(20); // will return 20 products per page
https://laravel.com/docs/5.7/pagination
Also, the collections() method on your Product model has product_id listed as the join table, and is joining to the CollectionProduct model instead of the Collection model.
Try this instead for your Product model:
public function collections()
{
return $this->belongsToMany(Collection::class, 'collection_products', 'product_id', 'collection_id');
}
i use following code and working very well
the first step get product
$product = Product()->find($product_id);
than i get collections and pagination
$collections = Product::find($product_id)->collections->paginate(20);
for example i used above code in this site.

Call to undefined relationship on model laravel using scope

I'm trying to get 5 posts for each category so I did a little search and ends up here Getting n Posts per category
But I'm getting a weird Call to undefined relationship on model when using with scope but it all works fine If I don't use a scope. Here is the Category Model
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
scopeNPerGroup
public function scopeNPerGroup($query, $group, $n = 10)
{
// queried table
$table = ($this->getTable());
// initialize MySQL variables inline
$query->from( \DB::raw("(SELECT #rank:=0, #group:=0) as vars, {$table}") );
// if no columns already selected, let's select *
if ( ! $query->getQuery()->columns)
{
$query->select("{$table}.*");
}
// make sure column aliases are unique
$groupAlias = 'group_'.md5(time());
$rankAlias = 'rank_'.md5(time());
// apply mysql variables
$query->addSelect(\DB::raw(
"#rank := IF(#group = {$group}, #rank+1, 1) as {$rankAlias}, #group := {$group} as {$groupAlias}"
));
// make sure first order clause is the group order
$query->getQuery()->orders = (array) $query->getQuery()->orders;
array_unshift($query->getQuery()->orders, ['column' => $group, 'direction' => 'asc']);
// prepare subquery
$subQuery = $query->toSql();
// prepare new main base Query\Builder
$newBase = $this->newQuery()
->from(\DB::raw("({$subQuery}) as {$table}"))
->mergeBindings($query->getQuery())
->where($rankAlias, '<=', $n)
->getQuery();
// replace underlying builder to get rid of previous clauses
$query->setQuery($newBase);
}
Calling Npergroup with relation
public function latestposts()
{
return $this->posts()->latest()->nPerGroup('category_id', 5);
}
Post Model Relationship
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
In my category controller I'm calling latestposts through
$categories = Category::with('latestposts')->get();
But I'm getting the error: Call to undefined relationship on model
What I want is:
Get the N number of posts per each category but I'm completely lost at this point. Any help would be appreciated
Reference:
Tweaking Eloquent relations – how to get N related models per parent ?
I am giving this answer based on your purpose that you want 5 posts per category.
So you have Category Model and Post Model.
And in Category Model you have relation with Post model like this
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
And in Post Model you have relation with Category model like this
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
I show your question you have done SQL queries.
Instead of that, You can use two approaches
1) Give condition while eagar loading
$categories = Category::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc')->take(5);
}])->get();
Note: This approach will only work when you take only one result of parent child using first() method.
To get n number of posts per category Use this.
First, you can retrieve all categories with
$categories = Category::all();
Then you can use foreach loop and in all $category you have to give assign new attribute in it like here latestposts,
foreach ($categories as $category)
{
$category->latestposts = $category->posts()->orderBy('created_at','desc')->take(5)->get();
}
After this foreach loop you will get latest 5 posts in all categories.
Try this in your code and comment your queries and reviews.

How OrderBy afterwards HasMany and BelongsTo Relationships

I created a relationship between the "Review, Games and Info" tables, unfortunately, though, the main table is Games, and he orders me all for Games, While I would like to order the ID of "review" table.
Models: Review
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id_gioco', 'id');
}
Models: Giochi
public function review()
{
return $this->belongsTo('App\Models\Review', 'id', 'id_gioco');
}
public function infogiochi()
{
return $this->belongsTo('App\Models\InfoGiochi', 'id', 'id_gioco');
}
Models: InfoGiochi
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id', 'id_gioco');
}
Controller:
$review = Giochi::with('Review','InfoGiochi')->orderBy('id','DESC')->get();
Here is a screenshot of my json:
How do I order content for review table IDs?
You have 2 options. You use a join and order in the sql statement or you order it after retrieving the results in the collection.
Using Join
Giochi::select('giocos.*')
->with('Review','InfoGiochi')
->leftJoin('reviews', 'reviews.id', '=', 'giocos.id_gioco')
->orderBy('reviews.id','DESC')
->get();
Sorting Collection
Giochi::with('Review','InfoGiochi')
->get()
->sortByDesc(function($giochi) {
return $giochi->review->id;
});
This would be the shortest version to sort on the collection:
Giochi::with('review')
->get()
->sortByDesc('review.id');
You can modify your relationship query when you fire it:
Giochi::with([
'Review' => function ($query) { return $query->orderBy('id','DESC'); },
'InfoGiochi'
])->orderBy('id','DESC');
You can try with a raw query or you can use ->orderBy() directly on review function.

Categories