Laravel - Рефакторинг разрешений пользователя "Gate :: Define" кода для упрощения чтения кода

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
6
0
1 381
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Тем не менее, вот несколько идей. Большая часть вашего кода - это соответствие между разрешением и реализацией политики. Например, '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() { /* ... */ }
}

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

Ответ принят как подходящий

Во-первых, автор этой статьи вообще не использовал политики, он создал таблицу разрешений, а затем привязал созданные им разрешения к воротам 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;
    }
});

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

Другие вопросы по теме