Laravel - 重构用户权限 "Gate::Define" 代码使代码更易于阅读
Laravel - Refactoring User Permission "Gate::Define" Code Into Easier to Read Code
所以我基本上想做的是将我的长代码重构为更简单的代码。我在 website 找到了这段代码,但我真的不明白代码中发生了什么。考虑到我使用的策略和方法与标准不同,我认为这段代码不会起作用。
来自网站的代码片段:
//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');
有没有办法根据我的权限 table 将此作为 foreach 循环执行?这是一些伪代码:
foreach($permissions as $permission) {
Gate::define($permission->slug, 'App\Policies\' . $permission->category . 'Policy@' . $permission->name);
}
问题:有什么方法可以使我的代码更紧凑,更易于阅读,就像网站上的代码片段一样?
就个人而言,您现有的代码很好。有用。它是可读的。虽然它可能会随着您的应用程序的增长而变得更加冗长,但也可能不会。那么为什么要改进它呢?
也就是说,这里有一些想法。您的大部分代码是权限和策略实现之间的映射。例如 'part.view'
映射到 'App\Policies\Parts\PartsPolicy@view
。此映射的"weight"无法删除:只能移动。
您可以考虑将其移动到一个更简单的配置文件中,如下所示:
// 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() { /* ... */ }
}
我个人不喜欢这个:它增加了一层内部框架,我发现其价值很难衡量。
首先,那篇文章的作者根本没有使用策略,他创建了一个权限table,然后通过代码片段[=]将他创建的权限绑定到laravel gates 24=]
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
});
});
为了使您的代码更加动态,我建议您执行以下操作:
数据库结构
创建permission
数据库table
创建roles
数据库table
创建 permission_role
数据透视表数据库 table
创建 role_user
数据透视表数据库 table
定义关系
角色有很多权限(多对多关系,用belongsToMany
定义)
权限属于多个角色(多对多关系,用belongsToMany
定义)
用户有多个角色(多对多关系,用belongsToMany
定义)
减少 global
权限的数量
通过利用Gate::before
,您可以允许具有global
或root
权限的特定用户授权所有定义的能力:
Gate::before(function ($user, $ability) {
if ($user->hasPermission('root-access')) {
return true;
}
});
如果您实施数据库权限,则不再需要为每个模型创建策略,并且将使用上述代码动态定义门。
所以我基本上想做的是将我的长代码重构为更简单的代码。我在 website 找到了这段代码,但我真的不明白代码中发生了什么。考虑到我使用的策略和方法与标准不同,我认为这段代码不会起作用。
来自网站的代码片段:
//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');
有没有办法根据我的权限 table 将此作为 foreach 循环执行?这是一些伪代码:
foreach($permissions as $permission) {
Gate::define($permission->slug, 'App\Policies\' . $permission->category . 'Policy@' . $permission->name);
}
问题:有什么方法可以使我的代码更紧凑,更易于阅读,就像网站上的代码片段一样?
就个人而言,您现有的代码很好。有用。它是可读的。虽然它可能会随着您的应用程序的增长而变得更加冗长,但也可能不会。那么为什么要改进它呢?
也就是说,这里有一些想法。您的大部分代码是权限和策略实现之间的映射。例如 'part.view'
映射到 'App\Policies\Parts\PartsPolicy@view
。此映射的"weight"无法删除:只能移动。
您可以考虑将其移动到一个更简单的配置文件中,如下所示:
// 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() { /* ... */ }
}
我个人不喜欢这个:它增加了一层内部框架,我发现其价值很难衡量。
首先,那篇文章的作者根本没有使用策略,他创建了一个权限table,然后通过代码片段[=]将他创建的权限绑定到laravel gates 24=]
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
});
});
为了使您的代码更加动态,我建议您执行以下操作:
数据库结构
创建
permission
数据库table创建
roles
数据库table创建
permission_role
数据透视表数据库 table创建
role_user
数据透视表数据库 table
定义关系
角色有很多权限(多对多关系,用
belongsToMany
定义)权限属于多个角色(多对多关系,用
belongsToMany
定义)用户有多个角色(多对多关系,用
belongsToMany
定义)
减少 global
权限的数量
通过利用Gate::before
,您可以允许具有global
或root
权限的特定用户授权所有定义的能力:
Gate::before(function ($user, $ability) {
if ($user->hasPermission('root-access')) {
return true;
}
});
如果您实施数据库权限,则不再需要为每个模型创建策略,并且将使用上述代码动态定义门。