ホームページ > バックエンド開発 > PHPチュートリアル > Laravel で動的で保守可能なメニューを構築する

Laravel で動的で保守可能なメニューを構築する

Patricia Arquette
リリース: 2024-12-14 22:28:12
オリジナル
164 人が閲覧しました

Laravel アプリケーションが成長するにつれて、特にロールベースのアクセス制御などの動的要素の場合、ナビゲーション メニューの管理が困難になることがあります。このブログ投稿では、メニュー ビルダー システムを使用してメニューを簡素化し、構造化し、メンテナンス、拡張、拡張を容易にする方法について説明します。


問題

多くの Laravel プロジェクトでは、Blade テンプレートは条件文を使用してメニューの可視性を処理します。

@can('viewAdmin')
    <a href="{{ route('administration.index') }}">
        {{ __('Administration') }}
    </a>
@endcan
ログイン後にコピー

このアプローチは単純なアプリケーションでは機能しますが、メニューの数が増えると乱雑になり管理できなくなります。


解決策

メニュー ビルダー システム は、メニュー ロジックを再利用可能なクラスにカプセル化し、以下を改善します。

  1. 保守性: 一元化されたメニュー定義。
  2. スケーラビリティ: 役割または権限に基づいてメニューを動的に生成します。
  3. 再利用性: ビュー間でメニューを共有します。

私の仕事を後援することで、開発者コミュニティに力を与えるという私の使命をサポートしてください。あなたの貢献は、貴重なツール、洞察、リソースを構築して共有するのに役立ちます。詳細については、こちらをご覧ください。


段階的な実装

1. viewAdmin のゲートを定義する

管理メニューへのアクセスを制御するには、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. Blade テンプレートでの使用法

ナビゲーション メニュー (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-スロット名="ヘッダー">{{ __('管理') }}</x-スロット>
    <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 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート