feat: Add frontend menu management system with permission filtering
This commit is contained in:
40
src/app/Models/Menu.php
Normal file
40
src/app/Models/Menu.php
Normal 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();
|
||||
}
|
||||
}
|
||||
90
src/app/Models/MenuItem.php
Normal file
90
src/app/Models/MenuItem.php
Normal 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user