feat: Add frontend menu management system with permission filtering

This commit is contained in:
2026-03-13 14:21:43 +02:00
parent 1995f58056
commit ed7055edaa
21 changed files with 1023 additions and 7 deletions

40
src/app/Models/Menu.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Menu extends Model
{
protected $fillable = [
'name',
'slug',
'location',
'is_active',
];
protected $casts = [
'is_active' => 'boolean',
];
public function items(): HasMany
{
return $this->hasMany(MenuItem::class)->whereNull('parent_id')->orderBy('order');
}
public function allItems(): HasMany
{
return $this->hasMany(MenuItem::class)->orderBy('order');
}
public static function findBySlug(string $slug): ?self
{
return static::where('slug', $slug)->where('is_active', true)->first();
}
public static function findByLocation(string $location): ?self
{
return static::where('location', $location)->where('is_active', true)->first();
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Auth;
class MenuItem extends Model
{
protected $fillable = [
'menu_id',
'parent_id',
'title',
'type',
'url',
'route',
'route_params',
'module',
'permission',
'icon',
'target',
'order',
'is_active',
];
protected $casts = [
'route_params' => 'array',
'is_active' => 'boolean',
'order' => 'integer',
];
public function menu(): BelongsTo
{
return $this->belongsTo(Menu::class);
}
public function parent(): BelongsTo
{
return $this->belongsTo(MenuItem::class, 'parent_id');
}
public function children(): HasMany
{
return $this->hasMany(MenuItem::class, 'parent_id')->orderBy('order');
}
public function getUrlAttribute(): ?string
{
return match ($this->type) {
'link' => $this->attributes['url'],
'route' => $this->route ? route($this->route, $this->route_params ?? []) : null,
'module' => $this->module ? route("{$this->module}.index") : null,
default => null,
};
}
public function isVisibleToUser(?User $user = null): bool
{
if (!$this->is_active) {
return false;
}
$user = $user ?? Auth::user();
if (!$user) {
return !$this->permission && !$this->module;
}
if ($user->hasRole('admin')) {
return true;
}
if ($this->permission) {
return $user->can($this->permission);
}
if ($this->module) {
return $user->can("{$this->module}.view");
}
return true;
}
public function getVisibleChildren(?User $user = null): \Illuminate\Support\Collection
{
return $this->children->filter(fn (MenuItem $item) => $item->isVisibleToUser($user));
}
}