How to get posts of followed users - laravel

I'm trying to make news feed page, but in this page I need to output articles ordered by date and also they must belong to the user, which authed user follows. I tried a few things and than realised that I have the wrong logic. So in user model I have:
function followers()
{
return $this->belongsToMany('App\User', 'followers', 'user_id', 'follower_id');
}
function follows()
{
return $this->belongsToMany('App\User', 'followers', 'follower_id', 'user_id');
}
function articles(){
return $this->hasMany('App\Article');
}
and than in article I have the relationships:
public function user()
{
return $this->belongsTo('App\User');
}
I don't know if I can simplly get all articles and than output the ones the user follows. I'm kind of confused.
here is the code I use in controller:
$followinguserarticle = Article::whereHas('user.follows', function($q) {
$q->where('id', auth()->id());
})
->latest()
->get();
And than I try to loop through them with:
#foreach($followinguserarticle as $followinguserarticles)
<a>followinguserarticles->title</a>
#endforeach

Use the whereHas():
Article::whereHas('user.followers', function($q) {
$q->where('id', auth()->id());
})
->latest()
->get();

You can eager load relationship on authed user instance
$authed = Auth::user();
$authed ->load('follows.articles');
Now you have articles of users whom users follows
foreach($authed->follows as $follow){
foreach($follow->articles as $article){
//Now you have access to each article
}
}

So the solution I found is like this:
//get list of follower ids
$follows = Auth::user()->follows->pluck('id');
//get articles of those that user follows
$articles = Article::whereIn('user_id',$follows)
->with('user')
->latest()
->limit(10)
->get();

Related

How to make a query with relations and order it by date of the relation in Laravel 9

I have the User model, I also have the Post model.
I would like to get 4 users through the newest posts of my entire Post model (taking into account that even a single user could have n number of newest posts) and then get the posts of each user (two for each user) obtained through of the relationship, something like that in case it is not understood very well
I have no problem getting the relationship from the blade, but what I can't get are the 4 users with the newest posts
User model
public function posts()
{
return $this->hasMany(Post::class);
}
Post model
public function user()
{
return $this->belongsTo(User::class);
}
This is the query I was doing, but this will simply return any 4 users (I guess by their id) and each user with their 2 newest posts, which is not what I need
User::query()
->whereHas('posts', function ($query){
$query->where('state', PostStateEnum::PUBLISHED)
->orderBy('updated_at')
->take(2);
})
->take(4)
->get();
ADD:
I have tried with join() but I get the same user
My code:
return User::query()
->join('posts', 'posts.user_id', '=', 'users.id')
->where('posts.state', '=', PostStateEnum::PUBLISHED)
->orderByDesc('posts.updated_at')
->select('users.*')
->with('posts', function ($query) {
$query->where('state', PostStateEnum::PUBLISHED)
->orderByDesc('updated_at')
->take(2)
->get();
})
->take(4)
->get();
that return 4 users, but all are the same user
I found subquery ordering
public function getUsersByNewerPosts()
{
return User::query()
->whereHas('posts', function ($query) {
$query->where('state', PostStateEnum::PUBLISHED);
})
->orderByDesc(
Post::select('updated_at')
->whereColumn('user_id', 'users.id')
->where('state', PostStateEnum::PUBLISHED)
->orderByDesc('updated_at')
->limit(1)
)
->take(4)
->get();
}

How to get top 5 tags of Category from posts Laravel

Hi I've 3 Modeles Post, Tag, and category , post belongs to many categories as well as tags. I want to fetch the top 5 tags of the posts for the given categories but there is no direct relationship between tags and categories.
Following is my eloquent relationship
// Post model
public function categories()
{
return $this->belongsToMany(Category::class, 'post_categories', 'post_id', 'category_id')->withTimestamps();
}
public function tags()
{
return $this->belongsToMany(Tag::class, 'post_tags', 'post_id', 'tag_id')->withTimestamps();
}
// Category Model
public function posts()
{
return $this->belongsToMany(Post::class, 'post_categories', 'category_id', 'post_id')->withTimestamps();
}
// Tag Model
public function posts()
{
return $this->belongsToMany(Post::class, 'post_tags', 'tag_id', 'post_id')->withTimestamps();
}
I have category $category = Category::find($id) for this $category I'm trying to get top 5 tags based on the posts related to this category
Please guide, Thanks in advance
How can I get the top 5 category tags from posts in Laravel?
Controller
$tags = Tag::whereHas('posts' , function (Builder $query) {
$query->whereHas('categories', function ($query,$categoryId) {
$query->where('id', $categoryId);
});
)})
->latest()
->limit(5)
->get();
Alright, I end up using joins
$tags = DB::table('tags')
->select('tags.id', DB::raw('COUNT(tags.id) as tags_count'), DB::raw('FIRST(tag.name)'))
->leftJoin('post_tags', 'tags.id', '=', 'post_tags.tag_id')
->leftJoin('posts', 'posts.id', '=', 'post_tags.post_id')
->leftJoin('post_categories', 'posts.id', '=', 'post_categories.post_id')
->leftJoin('categories', 'categories.id', '=', ''post_categories.category_id')
->where('categories,id', '=', $categoryId)
->groupBy('tags.id')
->orderBy('tags_count', 'DESC')
->limit(5)
->get();

Laravel: sort query results based on field of nested relationship

I have two models with relations as defined below
Order
public function owner()
{
return $this->belongsTo(User::class, 'owner_id');
}
User
public function company(){
return $this->belongsTo(Company::class, 'company_id');
}
company table have 'title' field.
what I want is to get all the orders sorted/order by company title. I've tried different solution but nothing seems to work. Any help or hint would be appreciated.
Recent solution that I tried is
$query = OrderModel::whereHas('owner', function($q) use ($request){
// $q->orderBy('owner');
$q->whereHas('company',function ($q2) use ($request){
$q2->orderBy('title',$request->get('orderByDirection') ?? 'asc');
});
});
but I am not getting user and company relation in query results. also the result remains same for 'ASC' and 'DESC' order.
You could sort the query after adding join like:
return Order::join('users', 'users.id', '=', 'owner_id')
->join('companies', 'companies.id', '=', 'users.company_id')
->orderBy('companies.title')
->select('orders.*')
->get();
You can define new relations in User and Company models.
User
public function orders()
{
return $this->hasMany(Order::class);
}
Company
public function users()
{
return $this->hasMany(User::class);
}
Now you can fetch companies that are in asc order and with the use of relation, you can fetch users and orders. So the ORM like be,
$companies = Company::with('users.orders')->orderBy('title', 'ASC')->get();
So these are the company-wise orders. You can use this too.

Property [***] does not exist on this collection instance Laravel eloquent relationship

In my Post Model
public function user()
{
return $this->belongsTo('App\User');
}
And in the User Model
public function posts()
{
return $this->hasMany('App\Post');
}
Now I am trying to get the comments of a specific user
$user= User::where('name', 'like', '%Mat%')->first();
return $user->posts->comment;
But it shows
Property [comment] does not exist on this collection instance.
The user has many posts which therefore returns a collection, you will need to loop over this to get your comments out. I.e.
$user = User::where('name', 'like', '%Mat%')->first();
$user->posts->each(function($post) {
echo $post->comment;
});
See the documentation on Laravel Collections
I think you can try this :
$user= User::with('post')->where('name', 'like', '%Mat%')->get();
$postComment = array();
foreach($user->post as $post){
$postComment = $post->comment;
}
return $postComment;
Hope this help for you !!!
If you want to have all comments you can use the following code:
$comments = [];
$user = User::where('name', 'like', '%Mat%')->with(['post.comment' => function($query) use (&$comments) {
$comments = $query->get();
}])->first();
return $comments;
Property [comment] does not exist on this collection instance.
The above error occurs because the Posts function returns a collection. Now you will have to traverse through each element of the collection.
Since, you are returning $user->posts()->comment, I am assuming you need it in the form of an array and don't have to simply echo them out, one by one. So you can store them all in an array & then process it whatever whay you like.
$comments = array();
$user->posts()->each(function $post){
$comments = $post->comment;
}
return $comments;
For greater insight, into this collection function read:
https://laravel.com/docs/5.4/collections#method-each

Return relationship only if user is logged in?

I have a Posts and a Comments table, where each post can have multiple comments.
I want to make a query that gets all posts, and also all of the logged in user's comments.
Here is what I have so far:
$posts = Post::select('posts.*')
->with(['comments' => function($query) {
if (Auth::check()) {
$query->where('user_id', Auth::user()->id);
}
}])
->get();
And my Post.php model class looks like this:
class Post extends Model
{
public function comments()
{
return $this->hasMany('App\Comment');
}
}
The query returns the correct results when the user is logged in.
But when the user is not logged in, it returns the comments of ALL users, instead of returning nothing (because the user is logged in and therefore they have no comments).
How can I fix this?
you can do a little trick in your post model:
class Post extends Model
{
public function comments()
{
if(Auth::check()) {
return $this->hasMany('App\Comment')->where('user_id', Auth::user()->id);
}else{
return $this->hasMany('App\Comment')->where('user_id',-1);
}
}
}
and then simply :
$posts = Post::select('posts.*')->with('comments')->get()
so if user is not logged in it will return all comments with user_id of "-1" which will be nothing
There are two ways I can think of to this.
First you can only load the comments if the user is logged in:
$posts = Post::select('posts.*');
if(Auth::check()) {
$posts->with(['comments' => function($query) {
$query->where('user_id', Auth::user()->id);
}]);
}
$posts = $posts->get();
Or you could load all comments but set the user_id to null if the user isn't logged in. Since every comment should have a user_id no comments will be returned.
$posts = Post::select('posts.*')
->with(['comments' => function($query) {
$query->where('user_id', Auth::check() ? Auth::id() : null);
}])
->get();
The code in the second one looks cleaner IMO, but the first one will prevent an unnecessary query from being executed.
You can separate it, more legible and practical:
$posts = Post::all();
At your Post model create a function that will return all user's comments:
public function userComments()
{
return $this->comments->where('user_id', Auth::user()->id);
}
And i guess at your view you have a foreach to iterate all posts, inside your foreach you load post's comments, so you can do that:
#foreach($posts as $post)
$post->userComments()
#endforeach

Resources