Search code examples
phplaravellaravel-5laravel-authorization

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?


Solution

  • 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.