$items */ public function __construct( public string $name, public array $items, public Icon|string|null $icon = null ) { } /** * Get icon as Icon object */ public function getIcon(): ?Icon { if ($this->icon === null) { return null; } if ($this->icon instanceof Icon) { return $this->icon; } return Icon::fromString($this->icon); } public static function fromArray(array $data): self { $items = []; $itemsData = $data['items'] ?? []; foreach ($itemsData as $key => $itemData) { // Handle legacy format: ['Item Name' => '/url'] if (is_string($itemData)) { $items[] = NavigationItem::fromArray([ 'name' => is_string($key) ? $key : 'Item', 'url' => $itemData, ]); } elseif (is_array($itemData)) { // Handle modern format: [['name' => 'Item Name', 'url' => '/url']] $items[] = NavigationItem::fromArray($itemData); } // Skip invalid formats } return new self( name: $data['section'] ?? $data['name'] ?? '', items: $items, icon: $data['icon'] ?? null // Can be string or Icon ); } public function toArray(): array { $icon = $this->getIcon(); return [ 'section' => $this->name, 'name' => $this->name, 'items' => array_map( fn (NavigationItem $item) => $item->toArray(), $this->items ), 'icon' => $this->icon instanceof Icon ? $this->icon->toString() : $this->icon, 'icon_html' => $icon?->toHtml('admin-nav__section-icon') ?? '', ]; } public function addItem(NavigationItem $item): self { return new self( name: $this->name, items: [...$this->items, $item], icon: $this->icon ); } public function hasActiveItem(string $currentPath): bool { foreach ($this->items as $item) { if ($item->isActive($currentPath)) { return true; } } return false; } }