首頁 >後端開發 >php教程 >在 Laravel 中建立動態且可維護的選單

在 Laravel 中建立動態且可維護的選單

Patricia Arquette
Patricia Arquette原創
2024-12-14 22:28:12165瀏覽

隨著 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>

            
  

            
        </x-app-layout>

以上是在 Laravel 中建立動態且可維護的選單的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn