首页 > 后端开发 > php教程 > 在 Laravel 中构建动态且可维护的菜单

在 Laravel 中构建动态且可维护的菜单

Patricia Arquette
发布: 2024-12-14 22:28:12
原创
162 人浏览过

随着 Laravel 应用程序的发展,管理导航菜单可能会变得具有挑战性,特别是对于基于角色的访问控制等动态元素。这篇博文探讨了如何使用菜单生成器系统简化和构建菜单,使它们更易于维护、扩展和扩展。


问题

在许多 Laravel 项目中,Blade 模板使用条件处理菜单可见性:

@can('viewAdmin')
    <a href="{{ route('administration.index') }}">
        {{ __('Administration') }}
    </a>
@endcan
登录后复制

虽然这种方法适用于简单的应用程序,但随着菜单数量的增加,它会变得混乱且难以管理。


解决方案

菜单生成器系统将菜单逻辑封装到可重用的类中,改进:

  1. 可维护性:集中菜单定义。
  2. 可扩展性:根据角色或权限动态生成菜单。
  3. 可重用性:跨视图共享菜单。

通过赞助我的工作来支持我为开发者社区赋能的使命——您的贡献帮助我构建和分享有价值的工具、见解和资源:在此处了解更多信息。


逐步实施

1.为 viewAdmin 定义一个 Gate

要控制对管理菜单的访问,请在 AuthServiceProvider 中定义 viewAdmin 门:

use Illuminate\Support\Facades\Gate;
use App\Models\User;

class AuthServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->registerPolicies();

        Gate::define('viewAdmin', function (User $user) {
            return $user->hasRole('admin'); // Replace with your app's role-checking logic
        });
    }
}
登录后复制

2.创建 MenuItem 类

MenuItem 类定义菜单项的所有属性,例如标签、URL、图标和可见性:

<?php

namespace App\Actions\Builder;

use CleaniqueCoders\Traitify\Contracts\Builder;
use InvalidArgumentException;

class MenuItem implements Builder
{
    private string $label;
    private string $url;
    private string $target = '_self';
    private array $attributes = [];
    private array $children = [];
    private string $icon = 'o-squares-2x2';
    private ?string $description = null;
    private ?string $tooltip = null;
    private $visible = true;
    private array $output = [];

    public function setLabel(string $label): self
    {
        $this->label = $label;

        return $this;
    }

    public function setUrl(string $url): self
    {
        $this->url = $url;

        return $this;
    }

    public function setTarget(string $target): self
    {
        $this->target = $target;

        return $this;
    }

    public function addAttribute(string $key, string $value): self
    {
        $this->attributes[$key] = $value;

        return $this;
    }

    public function addChild(MenuItem $child): self
    {
        $this->children[] = $child;

        return $this;
    }

    public function setIcon(string $icon): self
    {
        $this->icon = $icon;

        return $this;
    }

    public function setDescription(string $description): self
    {
        $this->description = $description;

        return $this;
    }

    public function setTooltip(string $tooltip): self
    {
        $this->tooltip = $tooltip;

        return $this;
    }

    public function setVisible($visible): self
    {
        if (! is_bool($visible) && ! is_callable($visible)) {
            throw new InvalidArgumentException('The visible property must be a boolean or a callable.');
        }

        $this->visible = $visible;

        return $this;
    }

    public function isVisible(): bool
    {
        return is_callable($this->visible) ? call_user_func($this->visible) : $this->visible;
    }

    public function build(): self
    {
        $this->output = [
            'label' => $this->label,
            'url' => $this->url,
            'target' => $this->target,
            'attributes' => $this->attributes,
            'icon' => $this->icon,
            'description' => $this->description,
            'tooltip' => $this->tooltip,
            'children' => array_filter(
                array_map(fn (MenuItem $child) => $child->build()->toArray(), $this->children),
                fn (array $child) => ! empty($child) 
            ),
        ];

        return $this;
    }

    public function toArray(): array
    {
        return $this->output;
    }

    public function toJson(int $options = 0): string
    {
        return json_encode($this->toArray(), $options, 512);
    }
}

登录后复制

3.创建菜单生成器

菜单构建器动态解析和构造菜单:

namespace App\Actions\Builder;

class Menu
{
    public static function make()
    {
        return new self;
    }

    public function build(string $builder)
    {
        $class = match ($builder) {
            'navbar' => Navbar::class,
            'sidebar' => Sidebar::class,
            'administration' => Administration::class,
            default => Navbar::class,
        };

        $builder = new $class;
        return $builder->build();
    }
}
登录后复制

使用辅助函数访问菜单:

<?php

use App\Actions\Builder\Menu;

if (! function_exists('menu')) {
    function menu(string $builder)
    {
        return Menu::make()->build($builder)->menus();
    }
}
登录后复制

4.管理菜单

在 Administration 类中定义特定于管理的菜单项:

<?php

namespace App\Actions\Builder\Menu;

use App\Actions\Builder\MenuItem;
use CleaniqueCoders\Traitify\Contracts\Builder;
use CleaniqueCoders\Traitify\Contracts\Menu;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;

class Administration implements Builder, Menu
{
    private Collection $menus;

    public function menus(): Collection
    {
        return $this->menus;
    }

    public function build(): self
    {
        $this->menus = collect([
            (new MenuItem)
                ->setLabel(__('Issues'))
                ->setUrl(url(config('telescope.path')))
                ->setTarget('_blank')
                ->setVisible(fn () => Gate::allows('viewTelescope'))
                ->setTooltip(__('View Telescope issues'))
                ->setDescription(__('Access application issues using Laravel Telescope'))
                ->setIcon('o-bug'), // Heroicon outline for a bug

            (new MenuItem)
                ->setLabel(__('Queues'))
                ->setUrl(url(config('horizon.path')))
                ->setTarget('_blank')
                ->setVisible(fn () => Gate::allows('viewHorizon'))
                ->setTooltip(__('Manage queues'))
                ->setDescription(__('Access Laravel Horizon to monitor and manage queues'))
                ->setIcon('o-cog'), // Heroicon outline for settings/tasks

            (new MenuItem)
                ->setLabel(__('Access Control'))
                ->setUrl(route('security.access-control.index'))
                ->setVisible(fn () => Gate::allows('viewAccessControl'))
                ->setTooltip(__('Manage access control'))
                ->setDescription(__('Define and manage access control rules'))
                ->setIcon('o-lock-closed'), 

            (new MenuItem)
                ->setLabel(__('Users'))
                ->setUrl(route('security.users.index'))
                ->setVisible(fn () => Gate::allows('viewUser'))
                ->setTooltip(__('Manage users'))
                ->setDescription(__('View and manage user accounts'))
                ->setIcon('o-user-group'), 

            (new MenuItem)
                ->setLabel(__('Audit Trail'))
                ->setUrl(route('security.audit-trail.index'))
                ->setVisible(fn () => Gate::allows('viewAudit'))
                ->setTooltip(__('View audit trails'))
                ->setDescription(__('Audit logs for security and activity tracking'))
                ->setIcon('o-document-text'), 
        ])->reject(fn (MenuItem $menu) => ! $menu->isVisible())
            ->map(fn (MenuItem $menu) => $menu->build()->toArray());

        return $this;
    }
}
登录后复制

5.定义路线

为管理页面添加以下路由配置:

<?php

use Illuminate\Support\Facades\Route;

Route::middleware(['auth:sanctum', 'verified', 'can:viewAdmin'])
    ->as('administration.')
    ->prefix('administration')
    ->group(function () {

        Route::view('/', 'administration.index')->name('index');

    });
登录后复制

6.在刀片模板中的用法

导航菜单 (navigation-menu.blade.php):

@can('viewAdmin')
    <a href="{{ route('administration.index') }}">
        <x-icon name="o-computer-desktop" />
        {{ __('Administration') }}
    </a>
@endcan
登录后复制

管理菜单 (administration/index.blade.php):

<x-app-layout>
    <x-slot name="header">{{ __('管理') }}</x-slot>;
    <div>




<hr>

<p><strong>输出</strong></p>

<p>这是您可以获得的最终输出:</p>

<p><img src="https://img.php.cn/upload/article/000/000/000/173418649412401.jpg" alt="Building Dynamic and Maintainable Menus in Laravel"></p>
<blockquote>
<p>通过赞助我的工作来支持我为开发者社区赋能的使命——您的贡献帮助我构建和分享有价值的工具、见解和资源:在此处了解更多信息。</p>
</blockquote>


<hr>

<h3>
  
  
  <strong>结论</strong>
</h3>

<p>这个<strong>菜单生成器系统</strong>通过以下方式简化了 Laravel 中的导航管理:</p>

<ol>
<li>集中菜单定义以提高可维护性。</li>
<li>使用角色或权限动态控制菜单可见性。</li>
<li>跨视图和布局重用菜单逻辑。</li>
</ol>

<p>通过采用这种方法,即使在复杂的应用程序中,您也可以无缝扩展您的导航系统。 </p>

<p>您可能想从数据库加载菜单详细信息并构建您想要的菜单。但对我来说,这已经足够好了。我没有项目要求我使用数据库驱动的菜单配置。</p>

<p>代码可以在这里找到。 </p>

<p>尝试一下并分享您的想法! ?</p>


<hr>

<p>照片由 Unsplash 上的 LinedPhoto 拍摄</p>


          </div>

            
  

            
        
登录后复制

以上是在 Laravel 中构建动态且可维护的菜单的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板