自定义 @can() 以显示 pages/sections 的权限覆盖

Customize @can() to show a permissions overlay for pages/sections

在工作中,我维护了一个相当复杂的 Laravel 应用程序,随着新功能的实现和改进,该应用程序仍在不断发展。

我们在这个系统中有 non-technical 管理员管理其他用户的权限,有时很难知道什么权限最终会阻止用户访问特定页面或什么可能会给用户过多的访问权限.更好的权限描述和模拟用户以查看他们有权访问的内容的能力已经是我们所做的事情。

除此之外,我们还想为 blade 模板中定义的权限切换叠加层,我们可能会使用

定义此权限
@can('update', $post)
    <!-- Menu button to update a $post -->
@endcan

@can('manage_user_roles_and_permissions')
    <!-- A table with many different functions 
         for managing user roles + permissions -->
@endcan

有什么方法可以修改 @can() 在 blade 模板中的工作方式,以便我可以添加一些 javascript 来显示一个部分开始和结束的弹出窗口,例如 "The permission 'Show Post' is needed for this menu button to show" 或 "To see the following section a user needs the 'Manage user roles and permissions' permissions"。或者如果我可以在该部分周围添加一个带有红色边框的 div 就更好了。

如何在 blade 模板中使用 @can() 来显示叠加层的地方添加额外的 javascript/html。

要解决此问题,我需要扩展 blade,请参阅 Laravel 文档中的 Extending Blade

以下是我所做的快速测试,只是为了看看这是否可行。 $value 在这种情况下是一个字符串,其中包含 blade 文件在被处理之前的内容。所以我可以使用 preg_match_all() 找到 @can 语句,然后在需要的地方附加我的 javascript。我可以用同样的方式找到 @endcan,但很难知道哪个 @endcan 属于哪个 @can,但从现在开始应该很容易匹配。

<?php

namespace App\Providers;

use Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Blade::extend(function($value)
        {
            $can_array = array();
            preg_match_all('/(\s*)@(can)\(([^\)]*)\)(\s*)/', $value, $matches);
            if (count($matches) > 0 && isset($matches[3])) {
                foreach ($matches[3] as $match) {
                    if (!in_array($match, $can_array)) {
                        $can_array[] = $match;
                    }
                }
            }
            foreach ($can_array as $ca) {
                $value = str_replace("@can(" . $ca . ")", "@can(" . $ca . ") \r\n <!-- My javascript code goes here! -->", $value);
            }
            // TODO need to figure out a better way to handle this
            $value = str_replace("@endcan", "@endcan \r\n <!-- Section ended here -->", $value);
            return $value;
        });
    }
...

我的源代码现在看起来是这样的,目标达到了!