Introduction
Roles and permissions are an important part of most applications, and as a result there has been a lot of packages built to make it easier for developers to implement.
The most popular Laravel roles and permissions
package built by Spatie has proven to solve most roles and permissions related problems, except a few parts:
- Role hierarchy
- Roles and permissions on a pivot table (
many to many
relationship)
In this post, I will talk about a Laravel package that allows you to assign roles and permissions to any Laravel model, or on a pivot table (many to many relationships), and also solves most of the problems highlighted above.
Basic usage
Before diving in, here is a basic illustration of how it can be used.
// Assign a 'Super Admin' role to this user
$user >assign(Role::SuperAdmin);
// Check the user role
$user >isSuperAdmin(); // or
$user >hasRole(Role::SuperAdmin);
// Check if the user can perform the operation
$user >canDeleteTransactions(); // or
$user >can(Permission::DeleteTransactions);
// Check if the user has multiple permissions
$user >holds(Permission::DeleteTransactions, Permission::BlockUsers);
Roles and permissions on many to many relationship (pivot table)
// Assign a 'Super Admin' role to this user on the selected model
$user >of($merchant) >assign(Role::SuperAdmin);
// Or check the user role like this
$user >of($merchant) >isSuperAdmin(); // or
$user >of($merchant) >hasRole(Role::SuperAdmin);
// Check if the user can 'delete transactions' on the selected model
$user >of($merchant) >canDeleteTransactions(); // or
$user >of($merchant) >can(Permission::DeleteTransactions);
// Check if the user has multiple permissions on the selected model
$user >of($merchant) >holds(Permission::DeleteTransactions, Permission::BlockUsers);
Installation
You can install the package via composer:
composer require ajimoti/roles and permissions
Once the package has been installed, run the command below, and you are set to use the package.
php artisan roles:install
Explanation
After installing the package, the following files are being made available to your application
-
AjimotiRolesAndPermissionsHasRoles
trait, -
appEnumsRole.php
-
appEnumsPermission.php
This trait should be imported to the eloquent model you would like to assign roles and permissions to. Below is a sample of how the import and use the trait:
use IlluminateFoundationAuthUser as Authenticatable;
use AjimotiRolesAndPermissionsHasRoles;
class User extends Authenticatable
{
use HasRoles;
// ...
}
Roles Declaration (appEnumsRole.php
)
This file is used when validating roles and permissions. You are expected to declare the roles available on this file, and assign permissions to them in the permissions()
method.
Below is a sample of what the role class can look like:
<?php
namespace AppEnums;
use AjimotiRolesAndPermissionsHelpersBaseRole;
final class Role extends BaseRole
{
const SuperAdmin = 'super_admin';
const Admin = 'admin';
const Customer = 'customer';
public static $useHierarchy = true;
/**
* Set available roles and their permissions.
*
* @return array
*/
final public static function permissions(): array
{
return [
self::SuperAdmin => [
Permission::DeleteProducts,
Permission::DeleteTransactions,
Permission::ViewTransactions,
],
self::Admin => [
Permission::EditProducts,
Permission::CreateProducts,
],
self::Customer => [
Permission::BuyProducts,
],
];
}
}
From the above class, the SuperAdmin
, Admin
and Customer
constants are the declared roles, and as you can see, each role has been assigned permissions in the permissions()
method.
Additionally, the role class has a $useHierarchy
property set to true
which means that the higher roles should inherit the permissions of their respective lower roles. As a result, the SuperAdmin
role is known to be the highest level role because it is the first constant declared in the class, while the Customer
role is believed to be the lowest level role as it appears last.
SuperAdmin > Admin > Customer
Hence, the SuperAdmin
role has inherited every other role permission,
Their permissions are as follows
Role | Permissions |
---|---|
SuperAdmin |
Delete products, Delete transactions, View transactions, Edit products, Create products, Buy products |
Admin |
Edit products, Create products, Buy products |
Customer |
Buy products |
You can read the official documentation to better understand the
Permission
class
Available methods
The example below explains some of the methods available on a model after installation.
use AppEnumsRole;
use AppEnumsPermission;
// Assign a 'Super Admin' role to this user
$user >assign(Role::SuperAdmin);
// Check if the user has the role
$user >hasRole(Role::SuperAdmin);
// Or check the user role like this
// $model >is{role_key}();
$user >isSuperAdmin();
// Check if the user can perform a operation
$user >can(Permission::DeleteTransactions);
// Or check if the user can perform the operation like this:
// $model >can{permission_key}();
$user >canDeleteTransactions();
// Check if the user has multiple permissions
$user >holds(Permission::DeleteTransactions, Permission::BlockUsers);
// Give a user a permission directly
$user >give(Permission::DeleteTransactions); // the user now has this permission
Roles and permissions on a many to many relationship (Pivot table)
Using the package on a many to many
relationship is slightly different from using it on a normal model. The following are required for the package to work correctly on a many to many
relationship:
- A pivot table is needed
- The pivot table MUST have a
role
column. This column will be used to keep track of the role assigned to the relationship. (if you want to use a different column name, you can set this in the config file). - A
belongsToMany
relationship for the pivot table must exist on one of the models.
Quick sample
The first step is to import the AjimotiRolesAndPermissionsHasRoles
trait and have a belongs to many
relationship on the model.
Let's assume we are building an application that allows merchants
to manage their users
, additionally, a user can be a member of many merchants, i.e a merchant has many users.
Hence we have a database structure like this:
users
id integer
name string
merchant
id integer
name string
merchant_user (the pivot table)
merchant_id integer
user_id integer
role string (nullable)
From the above database structure, here is an illustration of what the user model should look like:
use IlluminateFoundationAuthUser as Authenticatable;
use AjimotiRolesAndPermissionsHasRoles;
class User extends Authenticatable
{
use HasRoles;
// ...
public function merchants()
{
return $this >belongsToMany(Merchant::class);
}
// ...
}
After doing the above, the HasRole trait provides an of()
method that can be used to perform roles and permissions related logic between two models via the belongs to many relationships.
Usage
For the examples below, we would assume the variable $merchant
is set to a merchant with name wallmart
like so:
$merchant = Merchant::where('name', 'wallmart') >first();
use AppEnumsRole;
use AppEnumsPermission;
// Sample merchant
$merchant = Merchant::where('name', 'wallmart') >first();
// Assign a 'Super Admin' role to this user on the selected merchant (wallmart)
$user >of($merchant) >assign(Role::SuperAdmin);
// Check if the user has a super admin role on the selected merchant (wallmart)
$user >of($merchant) >hasRole(Role::SuperAdmin);
// Or check the user role like this
// $user >of($model) >is{role_key}();
$user >of($merchant) >isSuperAdmin();
// Check if the user can 'delete transactions' on the selected merchant (wallmart)
$user >of($merchant) >can(Permission::DeleteTransactions);
// Or check if the user can has the permissions like this
// $user >of($model) >can{permission_key}();
$user >of($merchant) >canDeleteTransactions();
// Check if the user has multiple permissions on the selected merchant (wallmart)
$user >of($merchant) >holds(Permission::DeleteTransactions, Permission::BlockUsers);
This is just a summary of a few things you can do with the package, a few other features still exists on the documentation.
Finally
If you find this useful, or you are searching for a package that supports roles and permissions on a many to many
relationship, roles in hierarchy, or declaration of roles and permissions as enum constants, this is the package to work with.