Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel - Refactoring User Permission "Gate::Define" Code Into Easier to Read Code

So what i'm basically trying to do is refactor my long bit of code to something more simpler. I found this snippet of code at this website and I don't really understand what's going on inside the code. I don't think that this snippet of code will work considering I am using different policies and methods then what's standard.

Code Snippet From Site:

//PermissionsServiceProvider.php 
public function boot()
 {
     Permission::get()->map(function($permission){
        Gate::define($permission->slug, function($user) use ($permission){
           return $user->hasPermissionTo($permission);
        });
     });
 }

Can someone please explain what exactly is going on in this bit of code?

My Code:

// Posts Policy
Gate::define('post.view', 'App\Policies\Blog\PostsPolicy@view');
Gate::define('post.create', 'App\Policies\Blog\PostsPolicy@create');
Gate::define('post.update', 'App\Policies\Blog\PostsPolicy@update');
Gate::define('post.delete', 'App\Policies\Blog\PostsPolicy@delete');
Gate::define('post.publish', 'App\Policies\Blog\PostsPolicy@publish');
Gate::define('post.edit', 'App\Policies\Blog\PostsPolicy@edit');
Gate::define('post.global', 'App\Policies\Blog\PostsPolicy@global');

// Categories Policy
Gate::define('category.view', 'App\Policies\Blog\CategoriesPolicy@view');
Gate::define('category.create', 'App\Policies\Blog\CategoriesPolicy@create');
Gate::define('category.update', 'App\Policies\Blog\CategoriesPolicy@update');
Gate::define('category.delete', 'App\Policies\Blog\CategoriesPolicy@delete');
Gate::define('category.edit', 'App\Policies\Blog\CategoriesPolicy@edit');
Gate::define('category.global', 'App\Policies\Blog\CategoriesPolicy@global');

// Tags Policy
Gate::define('tag.view', 'App\Policies\Blog\TagsPolicy@view');
Gate::define('tag.create', 'App\Policies\Blog\TagsPolicy@create');
Gate::define('tag.update', 'App\Policies\Blog\TagsPolicy@update');
Gate::define('tag.delete', 'App\Policies\Blog\TagsPolicy@delete');
Gate::define('tag.edit', 'App\Policies\Blog\TagsPolicy@edit');
Gate::define('tag.global', 'App\Policies\Blog\TagsPolicy@global');

// Parts Section Policy
Gate::define('part.section.view', 'App\Policies\Parts\PartSectionsPolicy@view');
Gate::define('part.section.create', 'App\Policies\Parts\PartSectionsPolicy@create');
Gate::define('part.section.update', 'App\Policies\Parts\PartSectionsPolicy@update');
Gate::define('part.section.delete', 'App\Policies\Parts\PartSectionsPolicy@delete');
Gate::define('part.section.edit', 'App\Policies\Parts\PartSectionsPolicy@edit');
Gate::define('part.section.global', 'App\Policies\Parts\PartSectionsPolicy@global');

// Parts Policy
Gate::define('part.view', 'App\Policies\Parts\PartsPolicy@view');
Gate::define('part.create', 'App\Policies\Parts\PartsPolicy@create');
Gate::define('part.update', 'App\Policies\Parts\PartsPolicy@update');
Gate::define('part.delete', 'App\Policies\Parts\PartsPolicy@delete');
Gate::define('part.edit', 'App\Policies\Parts\PartsPolicy@edit');
Gate::define('part.global', 'App\Policies\Parts\PartsPolicy@global');

// Admin Management Policy
Gate::define('admin.global', 'App\Policies\AdminManagementPolicy@global');

// User Management Policy
Gate::define('user.global', 'App\Policies\UserManagementPolicy@global');

Is there a way to do this as a foreach loop from my permissions table? Here's some Pseudo code:

foreach($permissions as $permission) {
    Gate::define($permission->slug, 'App\Policies\' . $permission->category . 'Policy@' . $permission->name);
}

Question: Any way to make my code more compact and easier to read like the code snippet from the website?

like image 800
J. Robinson Avatar asked Sep 08 '18 01:09

J. Robinson


1 Answers

First of all, the author of that article did not use policies at all, he created a permissions table and then bound the permissions he created to laravel gates by the code snippet

 Permission::get()->map(function($permission){
    Gate::define($permission->slug, function($user) use ($permission){
       return $user->hasPermissionTo($permission);
    });
 });

Let's break it line by line

Permission::get() // Query all permissions defined in permissions database table
->map(function($permission){ // Foreach permission do the following
   Gate::define($permission->slug, // Create new gate with the permission slug
   function($user) use ($permission){
      return $user->hasPermissionTo($permission); // the user table has many to many relation with permissions table, here we only check if $user is associated with $permission
   });
});

To make your code more dynamic, I suggest you to do the following:

Database structure

  1. Create permission database table

  2. Create roles database table

  3. Create permission_role pivot database table

  4. Create role_user pivot database table

Define Relationships

  1. Role has many permissions ( many to many relationship, define it with belongsToMany )

  2. Permission belongs to many roles ( many to many relationship, define it with belongsToMany )

  3. User has many roles ( many to many relationship, define it with belongsToMany )

Reduce the number of global permissions

By utilising Gate::before you can allow specific user who has global or root permission to authorise all defined abilities:

Gate::before(function ($user, $ability) {
    if ($user->hasPermission('root-access')) {
        return true;
    }
});

If you implement the database permissions you no longer need to create policies for every model, and the gates will be defined using the above code dynamically.

like image 102
Walid Ammar Avatar answered Oct 31 '22 22:10

Walid Ammar