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

jrdavidson's avatar

User Roles/Groups/Permissions

I'm working on what I should really structure my users as far as what to do for assigning them a role, group, permissions. My main struggle is how to store this data in my database.

As of right now my users have the following for their table. Pretty basic stuff.

Table: users
Fields id  username  first_name   last_name  email  password 

My initial thoughts were to just add on a column field for a group_id but that's as far as I know. Can someone else give some suggestions on what I should do?

0 likes
36 replies
davorminchorov's avatar
Level 53

Users and Roles is a many to many relationship, same goes for Roles and Permissions

Maybe this will give you an idea:

/**
 * Table Name: users
 */

id int primary key unsigned not null auto increment
username varchar (30) unique
password varchar(60)
email_address varchar (50) unique
first_name varchar (30)
last_name varchar (30)
active boolean
remember_token varchar nullable
created_at timestamp
deleted_at timestamp
updated_at timestamp

/**
 * Table Name: roles
 */

id int primary key unsigned not null auto increment
role varchar (30) unique
created_at timestamp
deleted_at timestamp
updated_at timestamp

/**
 * Table name: role_user 
 * Type: Pivot table 
 */
id int primary key unsigned not null auto increment
role_id int unsigned
user_id int unsigned
created_at timestamp
deleted_at timestamp
updated_at timestamp

/**
 * Table name: permissions
 */
id int primary key not null unsigned auto increment
permission varchar (30) unique
description text
active boolean
created_at timestamp
deleted_at timestamp
updated_at timestamp

/**
 * Table name: permission_role 
 * Type: Pivot table 
 */
id int primary key not null unsigned auto increment
permission_id int unsigned
role_id int unsigned
created_at timestamp
deleted_at timestamp
updated_at timestamp

Also, you can check out some of the ACL packages on github, how the database structure for these tables is set up.

3 likes
jrdavidson's avatar

Great response. How would user_groups work into this. For example my user groups would be one of only a "basic user, editor, administrator, owner"

davorminchorov's avatar

If it's an owner, it will have all of the possible roles, same goes for administrator except owner. For editor, it will have basic user and editor etc. Based on role permissions, you'll allow the specific role to have access to a route / action

1 like
jrdavidson's avatar

I was just asking because I have areas where I would like to display the group they belong to.

jrdavidson's avatar

Wow that is a lot to read. I wouldn't mind reading it soon. I"m just trying to figure out examples of each table.

jrdavidson's avatar

@Ruffles Do you have one example of each to get me to understand what data should generally look like when going into some of those tables?

davorminchorov's avatar

Something like this:

role_user table
--------------------------------
| id | user_id | role_id |
|----|--------------|-----------|
1   |      1         |    1    |
--------------------------------
2   |      1         |    2    |
--------------------------------
3  |       1         |    3    |
--------------------------------
4  |       1         |    4    |
--------------------------------
5  |       2         |    3    |
--------------------------------
6  |       2         |    4    |
--------------------------------
7  |       3         |    4    |
--------------------------------
8  |       4         |    2    |
--------------------------------
9  |       4         |    3    |
--------------------------------
10 |       4         |    4    |
--------------------------------

It will be similar for the permissions and roles (permission_role) pivot table

1 like
jrdavidson's avatar

@Ruffles Great however that I understood I was talking more about the permissions and roles table.

davorminchorov's avatar

There are a few ways to deal with permissions, but one way would be something like

permissions table
--------------------------------
id |  permission          | 
--------------------------------
1   |   create                 |   
--------------------------------
2  |   view                    |   
--------------------------------
3  |   update                |   
--------------------------------
4  |   delete                 |   
--------------------------------
5  |   download           |   
--------------------------------
6  |   upload                |   
--------------------------------
7  |   review                 |   
--------------------------------

roles table
--------------------------------
id |  role                     | 
--------------------------------
1   |  owner                  |   
--------------------------------
2   |  administrator                  |   
--------------------------------
3   |  editor                  |   
--------------------------------
4   |  basic user                  |   
--------------------------------

I didn't include the rest of the fields but you can just imagine them being there. As I said in my previous post, the permission_role pivot table will look similar to the role_user pivot table.

1 like
davorminchorov's avatar

Yeah I just updated my post.

You can check out some of the already built ACL packages on github or even use them.

One of these packages is laravel-acl by @kodeine , he/she might give you some more info on how to use it or even how to build one.

2 likes
jrdavidson's avatar

@kodeine Thank you. I am going to be working with making sure I have my databases and sample data in the database correct and then I'll come back to working with the actual code for authorizing users for different roles/permissions.

1 like
jrdavidson's avatar

@kodeine and @Ruffles I wanted to come back to this for a second. The reason being in my HTML table that displays the output of all the user's. I have a table heading of Role. For this fact I'm wondering if I should go back and just have a one to one relationship or how I should demonstrate that.

davorminchorov's avatar

Sure, you can go back, but you'll limit your design and you might not be able to extend it in the future.

Why do you want to go back? Is it too complex?

jrdavidson's avatar

Well like if I was mentioning before. If I want to display the role of user the person is in my HTML table its going to display many different ones.

jrdavidson's avatar

I guess it still comes back to my users only having one role at a time.

davorminchorov's avatar

You can display the highest role in the HTML table if you don't want all of them shown there.

jrdavidson's avatar

Oh wow. I did not think of that.

How would I echo out that value then?

davorminchorov's avatar

You have to build the query around it. Query scope might be useful here.

The query for the query scope might look something like this:

$role = Role::where('name', $roleName)->get('name');

When you build your query scope, add it to the main query where you get the users, or well, build a query just for that view if it's too specific.

jrdavidson's avatar

@Ruffles

Can you dive deeper into that because right now I am gathering the list of all my users in the database table called "users" and I have a relationship set up, which I believe is correct, and would like to do a with role ontop of the query like so. I did go back to do the original way you had suggested with the pivot table.

<?php namespace App\Http\Controllers;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\Users\UserRepository;
use App\User;

use Illuminate\Http\Request;

class UsersController extends Controller {

    /**
     * @var UserRepository
     */
    private $repository;

    public function __construct(UserRepository $repository)
    {
    $this->repository = $repository;
    }

    public function index()
    {
        $users = $this->repository->getAll();

        return view('users.index', compact('users'));
    }
}
@foreach ($users as $user)
    <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->present()->name() }}</td>
                <td>{{ $user->email }}</td>
        <td>{{ $user->role }}</td><-------------Not sure what to do with it.
            <td>Action Links Here</td>
    </tr>
@endforeach
<?php namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use App\Presenters\Contracts\PresentableInterface;
use App\Presenters\PresentableTrait;
use Hash;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract, PresentableInterface {

    use Authenticatable, CanResetPassword, PresentableTrait;

    //use RecordsActivity;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['first_name', 'last_name', 'username', 'email', 'password'];

    public function roles()
    {
        return $this->belongsToMany( 'App\Role', 'role_user' );
    }

}
davorminchorov's avatar

How are they shown right now? Do all of them show at:

 <td>{{ $user->roles }}</td>
jrdavidson's avatar

I am needing to figure out how I should eager load with my repositories because the roles are not being loaded inside the users repository with them.

<?php namespace App\Http\Controllers;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\Users\UserRepository;
use App\User;

use Illuminate\Http\Request;

class UsersController extends Controller {

    /**
     * @var UserRepository
     */
    private $repository;

    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }

    public function index()
    {
        $users = $this->repository->getAll();

        return $users;

        return view('users.index', compact('users'));
    }
}

I tried to do this:

$users = $this->repository->with(['roles'])->getAll();

Instead received the following error:

FatalErrorException in UsersController.php line 24:
Call to undefined method App\Repositories\Users\LoggingUserRepository::with()
davorminchorov's avatar

you should do that in the User Repository where you have the query, like:

return User::with('roles')->get();

also don't forget to remove the return $users before returning the view.

1 like
jrdavidson's avatar

Well here is what I have and maybe you can explain to me why its only collecting the all the roles assigned to the user at the start anyway or should I only add onto the query to retrieve the last role or what do you think would be my best case solution.

id   role_id   user_id
1   1               1
2   2       1
{
    id: 1,
    first_name: "Me",
    last_name: "Me",
    username: "meuser",
    email: "meuser@gmail.com",
    active: 1,
    created_at: "2015-04-02 16:04:51",
    updated_at: "2015-04-02 16:04:51",
    deleted_at: null,
    roles: [
        {
            id: 1,
            role: "Owner",
            description: "Full access to parts of system.",
            created_at: "2015-04-02 16:04:51",
            updated_at: "2015-04-02 16:04:51",
            deleted_at: null,
            pivot: {
                user_id: 1,
                role_id: 1
            }
        }
    ]
},
<?php

namespace App\Repositories\Users;

use App\User;
use App\Repositories\EloquentRepository;

class EloquentUserRepository extends EloquentRepository implements UserRepository
{
    public function __construct(User $model)
    {
        parent::__construct( $model );
    }

    public function getAllWithRole()
    {
        return $this->model->with(['roles'])->get();
    }
}
davorminchorov's avatar

Which view is this? is it the one where you show all the users and the (HTML) table is something like:

-----------------------------------------------------------------------------------
Username | Email Address        | Roles |  Actions      |
-----------------------------------------------------------------------------------
test           | test@example.com   | owner | Edit | Delete  |  
-----------------------------------------------------------------------------------

Let's see how you will show the roles first.

It might not even be needed to return only the highest role, because you actually want to know all of the roles for each user before you take any action. Presenting all of them on the screen might be a better idea.

<td>{{ $user->roles->role }}</td> // this should return you the role from the roles table. See if it returns all of them.

After you check the above, add a few more roles for your users and see how it looks like.

jrdavidson's avatar

I do like that idea however it would make sorting with my datatables plugin if I want to sort by type of role

Next

Please or to participate in this conversation.