Eloquent many-to-many-to-many - how to load distant relation easily - php

I have 3 tables; users, groups and permissions
In models I have the relationships set as belongsToMany
in user model:
public function groups() {
return $this->belongsToMany('Group');
}
in group model:
public function users() {
return $this->belongsToMany('User');
}
public function permissions() {
return $this->belongsToMany('Permission');
}
in permissions model:
public function groups() {
return $this->belongsToMany('Group', 'id');
}
many users - to - many groups
many groups - to - many permissions
I'm trying to get all the permissions a user has, and have no clue what the code for it should look like. Can anyone help?

This is how you can do it:
User::where('id', $id)->with(['groups.permissions' => function ($q) use (&$permissions) {
$permissions = $q->get()->unique();
}])->first();
// then
$permissions; // collection of unique permissions of the user with id = $id

It should look something like this if you are eager loading...
$user = User::where('id', $id)->with(['groups.permissions'])->first();

Related

why laravel 6 many-to-many relationship does not working?

Hi I simply want to get permissions of the role, I am trying following
$r = Role::find(1);
dd($r->permissions);
The above script does not return any permission however you can see there is data in the below tables. I also tried following but no luck
$role = Role::with('permissions')->where('id', 1)->first();
I have data in the table as you can see
Table:tes_permissions
Table: tes_roles
Table: tes_permission_role
And following are Models
class Permission extends Model
{
protected $table = 'tes_permissions'
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
And
class Role extends Model
{
protected $table = 'tes_roles';
public function permissions() {
return $this->belongsToMany('App\Permission', 'tes_permission_role', 'permission_id', 'role_id');
}
}
Can someone kindly guide me what can be the issue, I would appreciate.
You mixed the order of properties in the belongsToMany(). The third argument is specifying the ID for the model defining the relationship. So change to the following:
public function permissions() {
return $this->belongsToMany('App\Permission', 'tes_permission_role', 'role_id', 'permission_id');
}
And on the Permission model, also define it to be sure.
public function roles()
{
return $this->belongsToMany('App\Role', 'tes_permission_role', 'permission_id', 'role_id');
}

How to fetch data from database using nested many to many relationships in Laravel

I'm working on Laravel Access Control Level (ACL) system. where is table contains some many to many to relationship. User table has many to many belongsToMany with Role Table and inversely many to many Role has belongsToMany with User table.Again, Role table has many to many belongsToMany relationship with Permission table and inversely Permission has many to many belongsToMany with Role table.
I want to run a query from user table which is fetch the all permissions of a role. this role is assigned to current user through roles table.
Here is my code sample.
User Model
public function roles()
{
return $this->belongstoMany(Role::class);
}
Role Model
public function users()
{
return $this->belongsToMany(User::class);
}
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
Permission Table
public function roles()
{
return $this->belongsToMany(Role::class);
}
I've tried this query using egar loading...
public function hasPermission($permission)
{
if($this->roles()->with('permissions')->get()->pluck('permissions'))
{
return true;
}
return false;
}
But it always return false.
There are many ways to check if one of the roles has given permission.
One example, add hasPermission method to User.php model
public function hasPermission($permission = '') {
if ( empty($permisison) ) {
return false;
}
/*
Find all user roles that have given permission
*/
$rolesWithPermission = $this
->roles()
->whereHas('permissions', function($query) use ($permission) {
$query->where('name', $permission);
})
->get();
/*
If there is at least one role with given permission,
user has permission
*/
return $rolesWithPermission->count() > 0;
}
Or you can do one query with multiple joins between users, roles and permissions, and filter out the result with where('permissions.name', '=', $permission)

Laravel - Has many of self through

I have two models, User and Appointment. Users can have clients which are also users. These clients are referenced in appointments under client_id:
The appointment table looks like this:
Appointment
id|user_id|client_id
I'd like to pull all clients per user (uniques) but having difficulty crafting the relationship (hasManyThrough – User has many Users (clients) through Appointments).
Based on my understanding of the Laravel docs, the following should work:
User.php
public function clients()
{
return $this->hasManyThrough('App\User', 'App\Appointment', 'client_id', 'user_id', 'id');
}
-
Appointment.php
public function user()
{
return $this->belongsTo('App\User');
}
public function client()
{
return $this->belongsTo('App\User', 'client_id');
}
Alas it does not get me what I'm looking for. Should I craft my own query?
That's a little tricky. The documentation Has Many Through example is cascade like structure, which tells me that this type of relationship is not applicable to your case (but there are many undocumented things, so it could also be possible).
I propose the following relationships if you don't want to deal with undocumented cases:
User.php
public function appointmentsInWhichIsProvider()
{
return $this->hasMany('App\Appointment');
}
public function appointmentsInWhichIsClient()
{
return $this->hasMany('App\Appointment', 'client_id');
}
Appointment.php
public function user()
{
return $this->belongsTo('App\User');
}
public function client()
{
return $this->belongsTo('App\User', 'client_id');
}
If you want to get all the clients of an user, you can do something like this (not pretty at all, but should do the trick):
$user = User::find(1);
$userClients = [];
foreach ($user->appointmentsInWhichIsProvider as $appointment) {
array_push($userClients, $appointment->client);
}
var_dump($userClients) // Collection containing all the user clients.

Laravel - Eloquent: get posts from user with users post table

I searched a lot but could not find any answer about it, so I hope you could help me!
I have three tables: posts, users and post_users.
Post_users contains two columns: user_id and post_id.
I need to get all posts by an user with Eloquent. Any ideas?
Model User:
public function posts()
{
return $this->belongsToMany('App\Post', 'post_users', 'user_id', 'post_id');
}
Model Post:
public function users()
{
return $this->belongsToMany('App\User', 'post_users', 'post_id', 'user_id');
}
Try:
$user = User::find($id);
$allpost = $user->posts()->get();
var_dump($allpost);
The Laravel docs cover this pretty well but I had an issue with it when I first started as well. Check out Laravel Relationships for the fully write up.
// Inside your Post model
public function user() {
return $this->belongsTo('App\User');
}
// Inside your User model
public function posts() {
return $this->hasMany('App\Posts');
}
You can then create a query:
$posts = User::find(1)->posts;
Or you can filter it further..
$posts = User::find(1)->posts()->where('active', 1)->get();
You may need to change your paths for the hasMany() and belongsTo() if your model location and names are different.
As you wish. Relation between User and Post is many-to-many
- Defined relation
// In User model
public function posts(){
return $this->belongsToMany(Post::class);
}
// In Post model
public function users(){
return $this->belongsToMany(User::class);
}
- Table structure
- users
id
- posts
id
- post_user
user_id
post_id
- Get all post by a user
$posts = User::find($user_id)->posts
If you donot have relationship built, try this. However building relationships is preferred. PostUsers and Posts are assumed models of post-users and posts tables, and post as column of the posts table. this gives the posts of logged in user, but not tested.
$postusers=PostUsers::where(['user_id'=>Auth::user()->id])->get();
foreach($postusers as $postuser)
{
$posts=Posts::where(['post_id'=>$postuser->post_id)]->get();
foreach($posts as $post)
{
print_r($post->post);
}
}
Try this
From Controller :
dd(Auth::user()->posts);
App/User
public function posts()
{
return $this->belongsToMany('App\Entities\posts', 'post_users', 'user_id', 'post_id');
}
make relationship with post model on the user model:
public function posts()
{
return $this->hasMany(Post::class);
}
make relationship with user model on the post model:
public function User()
{
return $this->belongsTo(User::class);
}
in controller or Wherever you use:
$userPosts = User::find($user->id)->posts->where('status', 1);

Laravel 4 eager loading

I have a User model, a Recipe model, and a Cookbook model.
A User can 'own' many recipes. (User -OneToMany- Recipe)
A user has 'only one' Cookbook. (User -OneToOne- Cookbook)
Recipes that a user owns belong to his Cookbook.
One Recipe can belong to many Cookbook. (Recipe sharing) (Cookbook -ManyToMany- Recipe)
Many Users may LIKE Many Recipe. (User -ManyToMany- Recipe)
Many Users can follow Many Cookbook. (User -ManyToMany- Cookbook)
One User can have many friends who are Users (User -OneToMany- User)
What I want to do is load recipes for the currently logged in user.
I want to load the recipes owned by his friends and the recipes of all the cookbooks the logged in user is following.
class User extends Eloquent {
public function friends() {
return $this->belongsToMany('User', 'user_friends', 'user_id', 'friend_id');
}
public function cookbook() {
return $this->hasOne('Cookbook', 'owner_id', 'id');
}
public function recipes() {
return $this->hasMany('Recipe', 'owner_id', 'id');
}
public function followedCookbooks() {
return $this->belongsToMany('Cookbook','cb_followers', 'follower_id', 'cb_id');
}
}
class Recipe extends Eloquent() {
public function owner() {
return $this->belongsTo('User', 'owner_id', 'id');
}
public function cookbooks() {
return $this->belongsToMany('Cookbook', 'cb_recipes', 'recipe_id', 'cb_id');
}
}
class Cookbook extends Eloquent() {
public function owner() {
return $this->belongsTo('User', 'owner_id', 'id');
}
public function recipes() {
return $this->belongsToMany('Recipe', 'cookbooks_recipes', 'cookbook_id', 'recipe_id');
}
public function followers() {
return $this->belongsToMany('User', 'cb_followers', 'cb_id', 'follower_id');
}
}
What I did is this:
$user = Auth::user();
$friends = $user->friends();
$cookbooks = $user->followedCookbooks();
$recipes = array();
foreach($friends as $friend) {
$recipe = $friend->recipes();
array_push($recipes, $recipe);
}
foreach($cookbooks as $cookbook) {
$cbRecipes = $cookbook->recipes()
foreach($cbRecipes as $cbRecipe) {
array_push($recipes, $cbRecipe);
}
}
But this method would run a lot of SQL queries. How can I use eager loading to reduce the number of queries?
How about
$user = Auth::user();
$recipesFriends = $user->friends()->with('friends.recipes')->get();
$recipesCookbooks = $user->with('followedCookbooks')->with('followedCookbooks.recipes')->get();
If you want to go a bit further you can take a look at this answer: How to list out all items in a nested table in Laravel
You may try this:
$userData = Auth::user()->load('cookbook.recipes')
->load('friends.cookbook.recipes');
If you want to load friends recipes in a different variable then you may try this:
$userData = Auth::user()->load('cookbook.recipes')
->load('friends.cookbook.recipes');
$friendsData = $userData->friends;

Categories