'boolean', 'hidden' => 'boolean', 'is_external' => 'boolean', ]; /** * 동기화 비교 대상 필드 */ public static function getSyncFields(): array { return ['name', 'url', 'icon', 'sort_order', 'is_active', 'hidden', 'is_external', 'external_url']; } /** * 상위 메뉴 */ public function parent(): BelongsTo { return $this->belongsTo(GlobalMenu::class, 'parent_id'); } /** * 하위 메뉴 목록 */ public function children(): HasMany { return $this->hasMany(GlobalMenu::class, 'parent_id'); } /** * 이 글로벌 메뉴로부터 복제된 테넌트 메뉴 목록 */ public function tenantMenus(): HasMany { return $this->hasMany(Menu::class, 'global_menu_id'); } /** * 활성화된 메뉴만 조회 */ public function scopeActive($query) { return $query->where('is_active', true); } /** * 숨겨지지 않은 메뉴만 조회 */ public function scopeVisible($query) { return $query->where('hidden', false); } /** * 최상위 메뉴만 조회 */ public function scopeRoots($query) { return $query->whereNull('parent_id'); } /** * 정렬된 메뉴 조회 */ public function scopeOrdered($query) { return $query->orderBy('sort_order')->orderBy('id'); } /** * 메뉴 레벨 계산 (대메뉴=1, 중메뉴=2, 소메뉴=3) */ public function getLevel(): int { if (is_null($this->parent_id)) { return 1; } $parent = $this->parent; if ($parent && is_null($parent->parent_id)) { return 2; } return 3; } /** * 메뉴 섹션 조회 (GlobalMenu는 기본값 'main' 반환) */ public function getSection(): string { return 'main'; } /** * meta 데이터 조회 (GlobalMenu는 빈 배열 반환) */ public function getMeta(?string $key = null, mixed $default = null): mixed { return $key === null ? [] : $default; } /** * 계층 구조로 정렬된 전체 메뉴 트리 조회 */ public static function getMenuTree(): array { $menus = static::with('children.children') ->whereNull('parent_id') ->active() ->visible() ->ordered() ->get(); return $menus->toArray(); } }