Use whereHas and query pivot table - laravel

I have 3 table: tasks, users, group, and a pivot table group_user.
A task has user_id, group_id
A group_user pivot table has user_id, group_id
I want to query the tasks if the task belongs to a group of the user.
I don't want tasks from groups that the user doesn't belong to.
What I have so far:
public function index()
{
$userId = Auth::user()->id;
return TaskResource::collection(
Task::
latest()
->whereHas('group', function($query) use($userId) {
$query->where('group_id', '=', $userId); // = is wrong
})
->get()
);
}
This gives me empty results, I tried to think about it but my head hurts

You want to get the tasks that are related to the group (or groups) of a user.
I supposed the relation name between the user table and the group table is 'users', in the Group model.
$userId = auth()->id();
$tasks = Task::latest()
->whereHas('group', function($query) use ($userId) {
$query->whereHas('users', function($query) use ($userId) {
$query->where('user_id', $userId);
});
})
->get();

Ive not tested this but i imagine you could nest the where has and use something like this in your whereHas block:
$query->whereHas('user', function($q2) use ($userId) {
$q2->where('user_id', $userId);
});

Related

Laravel - Many To Many return child records filtered

I have a User model which has a M:M relationship with Role model (I use roles_user intermediate table for M:M relationship)
The intermediate table has a column "Active" which defines which of the multiple roles assigned to a User is the active one.
So, I'm trying to retrieve a User with all the relationships it has an also only the active role.
For that, I'm executing the following code https://laravel.com/docs/6.x/eloquent-relationships#querying-relationship-existence:
public function index()
{
$users = User::whereHas('roles', function (Builder $query) {
$query->where('active', true);
})->get();
foreach ($users as $user) {
dd($user->roles);
}
return view('pages.admin.users.index', compact('users'));
}
When I dd the collection, I have the 5 records in intermediate table and not just the active one which I'm filtering:
What I am doing wrong?
You need to specify how you want to load the relationship:
This gets users that have atleast one "active" role
$users = User::whereHas('roles', function (Builder $query) {
$query->where('active', true);
})->get();
However, this line loads all roles regardless of their status.
dd($user->roles);
What you need is to get all users that have atleast one active role, and load only active roles on that user:
$users = User::whereHas('roles', function (Builder $query) {
$query->where('active', true);
})
->with(['roles' => function($query) {
$query->where('active', true);
}])
->get();

Grouping related models by pivot

I'm trying to group related model by pivot data, but this returns only one record of the related for each group. How can I group quiz records by column parent, which is saved in pivot table?
$user = User::where('id', $id)
->with(['quiz' => function($query) use ($md) {
$query->where('md_id',$md)->groupBy('pivot_parent');
}])
->first();
Try this and let me know what did you got
$user= User::where('id', $id)->whereHas('quiz', function($query)
use($md){
$query->where('md_id', '=', $md)-
>groupBy('pivot_parent');
})->first();

Laravel, where, orwhere in main table an pivot table

I have two tables with belongsToMany relation: message_topics and users
The pivot table is message_topics_users and contains 2 columns: message_id and user_id.
In table message_topics, I have a field called sender_id
I'm trying to write the correct eloquent syntax to get all the records:
where message_topics.sender_id = $user_id
OR Message_topics_users.receiver_id = $user_id
I tried many things, like for instance:
$topics = MessageTopic::where('sender_id', $user_id)
->wherePivot('receiver_id', $user_id)->orderBy('sent_at','desc')->get();
Any idea?
You can use the whereHas method (or in this case the orWhereHas method):
$topics = MessageTopic::where('sender_id', $user_id)
->orWhereHas('users', function ($query) use ($user_id) {
$query->where('id', $user_id);
})
->orderBy('sent_at', 'desc')
->get();
I'm assuming you have two relationships from the topics? Since it's too arbitrary to use both columns and the same relationship... Like this
//On your MessageTopic model
public function sender(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'sender_id');
}
public function receiver(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'receiver_id'));
}
Then you can use whereHas and orWhereHas like this:
//Again assuming you have your User model loaded as $user
$topics = App\Topic::whereHas('sender', function($q) use($user){
$q->where('sender_id', '=', $user->id);
})
->orWhereHas('receiver', function($q) use($user){
$q->where('receiver_id', '=', $user->id
})
->orderByDesc('sent_at')
->get();
whereHas and orWhereHas both query the model (MessageTopic in this case) checking for the existence of the specified relationship (App\Topic::whereHas('sender')...). They also allow you to pass the constraint that you're looking for (function($q) use($user){ $q->... })
So it is basically saying "Give me ONLY the MessageTopics that have a Sender or Receiver with the id $user->id"

eloquent where id in from many to many

users
id
roles
id
name
user_roles
user_id
role_id
I would like to query all users with specific roles.
e.g. get all users that have the role 'admin'
So, you can use the whereHas from Eloquent
$users = User::whereHas('roles', function($query) {
$query->where('name', 'admin');
})->get();
See here for reference https://laravel.com/docs/5.5/eloquent-relationships
There is also the option to go at the relationship from the other direction:
Role::where('name', 'admin')->firstOrFail()->users;
If you know role ID, do this:
User::whereHas('roles', function ($q) use($roleId) {
$q->where('id', $roleId);
})
->get();
If you know only name or title of the role, do this:
User::whereHas('roles', function ($q) use($roleTitle) {
$q->where('title', $roleTitle);
})
->get();

How to query a table using result of many-to-many relation with Eloquent ORM?

here is link to my database schema:
How can I get all topics from the blogs to which the user is subscribed using his id? I use Eloquent ORM.
I have added the following lines to my User model:
public function blogs()
{
return $this->belongsToMany('Blog', 'blog_subscriptions');
}
And then requested in the controller
User::find(1)->blogs; // User id is hardcoded
With that I got all blogs to which the user is subscribed.
And now I am stuck on how to get the topics of those blogs.
Assuming relations:
// User
belongsToMany('Blog', 'user_subscriptions')
// Blog
belongsToMany('User', 'user_subscriptions')
hasMany('Topic')
// Topic
belongsTo('Blog')
1 My way, that will work with any relation, no matter how deeply nested:
User::with(['blogs.topics' => function ($q) use (&$topics) {
$topics = $q->get()->unique();
}])->find($userId);
2 Eloquent standard methods:
$topics = Topic::whereHas('blog', function ($q) use ($userId) {
$q->whereHas('users', function ($q) use ($userId) {
$q->where('users.id', $userId);
});
})->get();
// or
$user = User::find($userId);
foreach ($user->blogs as $blog)
{
$blog->topics; // collection of topics for every single blog
}
3 Joins:
$topics = Topic::join('blogs', 'topics.blog_id', '=', 'blogs.id')
->join('user_subscriptions as us', function ($j) use ($userId) {
$j->on('us.blog_id', '=', 'blogs.id')
->where('us.user_id', '=', $userId);
})->get(['topics.*']);
Mind that last solution will rely on your pivot data consistency. That said, if you can't be sure, that there are no redundant entries in user_subscriptions (eg. blog or user has been deleted but the pivot entry remains), then you need to further join users as well.
I am new to laravel and I don't have the possibility of test this, but I had a similar need and solved it with something like this:
DB::Query('topics')->join('blogs', 'blogs.id', '=', 'topics.blog_id')
->join('blog_subscriptions', 'blogs.id', '=', 'blog_subscriptions.blog_id')
->select('name.id','table.email')
->where('blog_subscriptions.user_id', '=', $user_id);

Resources