Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

opheliadesign's avatar

Need help with Many to Many through Many to Many Eloquent

Hi everyone,

I am working on a new Laravel 5 app and have a bit of a tricky problem. First, check out this SO question - http://stackoverflow.com/questions/28440925/laravel-5-eloquent-orm-many-to-many-through-many-to-many

Basically, I have User Groups and User Permissions. A user may be granted permissions if they are assigned to a Group that has those permissions. In other words, a User may belong to many Groups, a Group may have many Permissions. A User may have a Permission THROUGH a Group.

There are three tables in the mix here - Users, Permissions ("Privileges" in this case), and User Groups. There is a pivot table between Users and User Groups and User Groups and Permissions.

Been a bit dismayed that I have not had much help on SO, only one comment stating that it is unclear what the question is - this is one of the most detailed questions I've ever posted, even including my complete table structure.

Any help would be greatly appreciated. I can make this work with Fluent query builder but I'm trying to make this app as Laravel 5-like as possible, using Eloquent relations.

Thanks!

0 likes
9 replies
jekinney's avatar

Taking a quick look at the linked question and your on the right track. But I gather you want only groups the have permission directly and not users? So users inherited permissions from groups they are assigned.

The tables should be: User, permissions, groups. Pivot tables: group_user, group _permissions. You could add a permissions _user if you wanted to, but not necessary.

Set up your model classes as with the video and relationships. Depending on your design pattern you need to loop through the users groups and there permissions.

If what I am trying to say is on the right track let us know and can go into further detail.

jekinney's avatar

The design pattern would clue me in to where you would perform the permissions check.

(can't edit posts from mobile).

nolros's avatar

@JarekTkaczyk is the Zen master of relationships. If he has a second maybe he can help. He would know the answer, but let me post my initial thinking.

   // pivot tables
    'role_users'
    'group_members'
    'users_groups'
    'users_permissions'
    'groups_permissions'

    // User model
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function roles()
    {
        return $this->belongsToMany('role', 'role_users', 'user_id', 'role_id')->withTimestamps();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function groups()
    {
        return $this->belongsToMany('group', 'group_members', 'user_id', 'group_id')->withTimestamps();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function permissions()
    {
        return $this->belongsToMany('permissions', 'user_permissions', 'permission_id', 'user_id')->withTimestamps();
    }

    // Role model
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function users()
    {
        return $this->belongsToMany('user', 'role_users', 'role_id', 'user_id')->withTimestamps();
    }

    //Group model
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function members()
    {
        return $this->belongsToMany('user', 'users_groups', 'group_id', 'user_id')->withTimestamps();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function permissions()
    {
        return $this->belongsToMany('permissions', 'groups_permissions', 'permission_id', 'group_id')->withTimestamps();
    }

    // Permission model
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function users()
    {
        return $this->belongsToMany('user', 'users_permissions', 'user_id', 'permission_id')->withTimestamps();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function groups()
    {
        return $this->belongsToMany('groups', 'groups_permissions', 'group_id', 'permission_id')->withTimestamps();
    }

    // Example of call
    /**
     * @param Group $group
     * @return mixed
     */
    public function findAllInGroup(Group $group)
    {
        return $group->members()->get();
    }
JarekTkaczyk's avatar

@opheliadesign My friend, your question is definitely not clear - after reading it, I have no idea what is that you need help with...

So better do this: How to check if user has priviledge either by himself or by the group he is in? Only then add the details of your implementation.

Is it what you asked for?

opheliadesign's avatar

Wow, lots of replies! Thanks everyone..

@JarekTkaczyk bit confused as to what you are saying. Are you suggesting a change in how I ask my question? The title is not the best, I did not know how else to phrase it at the time. But I feel that the content of the post(s) explains what I am trying to accomplish, don't know how else to describe it.

The simple questions I am trying to ask my app - "Does this User belong to a Group that has this specific Permission? If not, were they assigned this Permission directly (not belonging to any Groups)?" Basically, I am trying to allow the Admin users to group large volumes of Users together and assign them all the same Permissions without having to fill up my user_privelege pivot table.

@hostianer Thanks, this looks awesome! But unfortunately it does not seem to do what I am looking for. Simply belonging to a Group does not necessarily mean having a certain Permission. So it's more "does the User inherit a Permission through a Role?"

Here is the code that I used in my last Laravel 4.2 app. I want to somehow handle this using plain vanilla Laravel if possible. Note that in this example, "Groups" is "Levels", "Permissions" is "Roles" - it was not the best table layout.

<?php
class checkAccess {
    /**
     * @var array Array of level IDs associated with a User
     */
    private static $levelIDs;
    /**
     * @var string Role that we are searching for
     */
    private static $role;
    /**
     * Initialize
     *
     * Initializes the class
     */

    /**
     * Check Role Access
     *
     * Checks to see if a user has access to a particular role.
     *
     * @param string $role The name of the role we are checking for
     * @return bool True if the user has access, false if not
     */
    public static function check($role) {
        $id = Auth::user()->id; // Use the currently logged in user's ID
        $user = User::with('Levels')->find($id);
        if (count($user->levels) == 0) {
            // The user does not belong to any level groups
            return false;
        }
        self::$role = $role;
        $levels = $user->levels;
        foreach ($levels as $level) {
            if ($level->id == 1)
            {
                // This is an Admin user, we do not need to continue
                return true;
            }
            self::$levelIDs[] = $level->id;
        }
        return self::checkRoles();
    }

    /**
     * Check Roles
     *
     * Checks to see if the user is part of a level that includes this Role.
     *
     * @return bool True if a match is found, otherwise False
     */
    private static function checkRoles()
    {
        $roleListing = array();

        $roles = DB::table('level_role')->join('roles', 'level_role.role_id', '=', 'roles.id')->whereIn('level_role.level_id', self::$levelIDs)->select('roles.name')->get();
        if (!$roles) {
            return false;
        }
        foreach ($roles as $role) {
            $roleListing[] = $role->name;
        }

        if (in_array(self::$role, $roleListing)) {
            return true;
        } else {
            return false;
        }
    }
}

This is called like so:

if (checkAccess::check('Schedule Manager')) {
    // Continue
}
opheliadesign's avatar

@hostianer Actually, I missed the second link - hadn't had my coffee yet. These two resources might actually work perfectly. Thanks for sharing them! I'm still a bit curious if what I was trying to accomplish is possible with just Eloquent. A simple "no, it's not possible" would help.

Thanks again, everyone! Was nice to wake up and find so many great posts and ideas!

1 like
opheliadesign's avatar

@hostianer Zizaco/entrust is EXACTLY what I was looking for, it does exactly what I described. Not sure why nobody else mentioned this to me. Setting it up now, looks good. Thanks again for sharing this with me. :)

Please or to participate in this conversation.