Laravel - Рефакторинг кода разрешения «Gate :: Define» для пользователя, чтобы его было легче читать - PullRequest
0 голосов
/ 08 сентября 2018

Так что я в основном пытаюсь сделать рефакторинг моего длинного кода на что-то более простое. Я нашел этот фрагмент кода на этом веб-сайте , и я не совсем понимаю, что происходит внутри кода. Я не думаю, что этот фрагмент кода будет работать, учитывая, что я использую другие политики и методы, отличные от стандартных.

Фрагмент кода с сайта:

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

Может кто-нибудь объяснить, что именно происходит в этом фрагменте кода?

Мой код:

// 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');

Есть ли способ сделать это как цикл foreach из моей таблицы разрешений? Вот некоторый псевдокод:

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

Вопрос: Есть ли способ сделать мой код более компактным и легким для чтения, например, фрагмент кода с веб-сайта?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Прежде всего, автор этой статьи вообще не использовал политики, он создал таблицу разрешений, а затем привязал созданные разрешения к воротам Laravel с помощью фрагмента кода

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

Давайте разберем это строка за строкой

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
   });
});

Чтобы сделать ваш код более динамичным, я предлагаю вам сделать следующее:

Структура базы данных

  1. Создать permission таблица базы данных

  2. Создать roles таблица базы данных

  3. Создать permission_role сводную таблицу базы данных

  4. Создать role_user сводную таблицу базы данных

Определить отношения

  1. Роль имеет много разрешений (отношение «многие ко многим», определите ее с помощью belongsToMany)

  2. Разрешение принадлежит многим ролям (отношения многие ко многим определяют его с помощью belongsToMany)

  3. У пользователя много ролей (отношение «многие ко многим», определите его с помощью belongsToMany)

Уменьшить количество global разрешений

Используя Gate::before, вы можете разрешить конкретному пользователю, у которого есть права global или root, авторизовать все определенные способности:

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

Если вы реализуете разрешения для базы данных, вам больше не нужно создавать политики для каждой модели, и ворота будут определяться с использованием приведенного выше кода динамически.

0 голосов
/ 13 сентября 2018

Лично ваш существующий код в порядке. Оно работает. Это читабельно. Хотя оно может стать более многословным по мере роста вашего приложения, оно также может и не быть. Так зачем его улучшать?

Тем не менее, вот некоторые идеи. Большая часть вашего кода представляет собой соответствие между разрешением и реализацией политики. Например, 'part.view' отображается на 'App\Policies\Parts\PartsPolicy@view. «Вес» этого отображения не может быть удален: его можно только перемещать.

Возможно, вы захотите переместить его в более простой файл конфигурации, примерно такой:

// config/permission-map.php
<?php return [
    'post.view' => 'App\Policies\Blog\PostsPolicy@view',
    'post.create' => 'App\Policies\Blog\PostsPolicy@create',
    'post.update' => 'App\Policies\Blog\PostsPolicy@update',
    'post.delete' => 'App\Policies\Blog\PostsPolicy@delete',
    // etc...
];

Затем в своей загрузке вы читаете эту конфигурацию и выполняете итерацию:

// boot permissions
$permission_map = require_once('config/permission_map.php');
foreach ($permission_map as $permission => $policy_implementation) {
    Gate::define($permission, $policy_implementation);
}

Преимущество: добавление нового сопоставления политики изменяет только наиболее значимую информацию, и вам не нужно думать о том, как сделать это сопоставление - сегодня это Gate::define, а завтра, может быть, Sentry::policy. Кроме того, отделяя данные от кода, вы можете тестировать код более свободно.

Другим подходом могут быть аннотации: в DocBlock вашей реализации политики вы пишете собственный синтаксис аннотаций, который затем анализируете и компилируете в файл конфигурации. По линии

namespace App\Policies\Blog;

class PostsPolicy {
    /**
     * @permission post.view
     */
    public function view() { /* ... */ }
}

Лично я не фанат этого: он добавляет слой внутренней структуры, значение которой мне трудно измерить.

...