strtolower(trim((string) $r)), $roles))); $cacheKey = 'navbar_' . md5(json_encode($roles)); return Cache::remember($cacheKey, 300, function () use ($roles) { $allowedIds = RoleNavItem::getNavItemIdsForRoles($roles); if (empty($allowedIds)) { return []; } $rows = NavItem::query() ->where('is_enabled', 1) ->orderBy('menu_parent_id', 'asc') ->orderBy('label', 'asc') ->orderBy('id', 'asc') ->get() ->toArray(); $byId = []; foreach ($rows as $row) { if (in_array((int) $row['id'], $allowedIds, true)) { $row['children'] = []; $byId[$row['id']] = $row; } } $tree = []; foreach ($byId as $id => &$node) { $pid = $node['menu_parent_id'] ?? null; if ($pid && isset($byId[$pid])) { $byId[$pid]['children'][] = &$node; } else { $tree[] = &$node; } } unset($node); $this->sortTreeAlpha($tree); return $tree; }); } public function clearCache(): void { Cache::flush(); } private function labelKey(string $s): string { $s = trim(preg_replace('/\s+/', ' ', $s)); $s = preg_replace('/^[^[:alnum:]]+/u', '', $s); $s = preg_replace('/^(?i)(the|an|a)\s+/', '', $s); return mb_strtolower($s, 'UTF-8'); } private function sortTreeAlpha(array &$nodes): void { usort($nodes, function ($a, $b) { $result = strnatcasecmp($this->labelKey($a['label'] ?? ''), $this->labelKey($b['label'] ?? '')); return $result !== 0 ? $result : ((int) ($a['id'] ?? 0) <=> (int) ($b['id'] ?? 0)); }); foreach ($nodes as &$node) { if (!empty($node['children'])) { $this->sortTreeAlpha($node['children']); } } unset($node); } }