Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
NavItem
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
12 / 12
14
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 fromRoute
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 forLink
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 forRoute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDestination
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLabel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPriority
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroup
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isCurrent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRouteGroup
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 normalizeGroupKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Framework\Features\Navigation;
6
7use Hyde\Foundation\Facades\Routes;
8use Hyde\Hyde;
9use Hyde\Support\Models\Route;
10use Illuminate\Support\Str;
11use Stringable;
12
13/**
14 * Abstraction for a navigation menu item. Used by the NavigationMenu and DocumentationSidebar classes.
15 *
16 * You have a few options to construct a navigation menu item:
17 *   1. You can supply a Route directly and explicit properties to the constructor
18 *   2. You can use NavItem::fromRoute() to use data from the route
19 *   3. You can use NavItem::forLink() for an external or un-routed link
20 */
21class NavItem implements Stringable
22{
23    public readonly string $destination;
24    public readonly string $label;
25    public readonly int $priority;
26    public readonly ?string $group;
27
28    /**
29     * Create a new navigation menu item.
30     */
31    public function __construct(Route|string $destination, string $label, int $priority = 500, ?string $group = null)
32    {
33        $this->destination = (string) $destination;
34        $this->label = $label;
35        $this->priority = $priority;
36        $this->group = $group;
37    }
38
39    /**
40     * Create a new navigation menu item from a route.
41     */
42    public static function fromRoute(Route $route, ?string $label = null, ?int $priority = null, ?string $group = null): static
43    {
44        return new static(
45            $route->getLink(),
46            $label ?? $route->getPage()->navigationMenuLabel(),
47            $priority ?? $route->getPage()->navigationMenuPriority(),
48            $group ?? static::getRouteGroup($route),
49        );
50    }
51
52    /**
53     * Create a new navigation menu item leading to an external URI.
54     */
55    public static function forLink(string $href, string $label, int $priority = 500): static
56    {
57        return new static($href, $label, $priority);
58    }
59
60    /**
61     * Create a new navigation menu item leading to a Route model.
62     *
63     * @param  \Hyde\Support\Models\Route|string<\Hyde\Support\Models\RouteKey>  $route  Route model or route key
64     * @param  int|null  $priority  Leave blank to use the priority of the route's corresponding page.
65     * @param  string|null  $label  Leave blank to use the label of the route's corresponding page.
66     * @param  string|null  $group  Leave blank to use the group of the route's corresponding page.
67     */
68    public static function forRoute(Route|string $route, ?string $label = null, ?int $priority = null, ?string $group = null): static
69    {
70        return static::fromRoute($route instanceof Route ? $route : Routes::getOrFail($route), $label, $priority, $group);
71    }
72
73    /**
74     * Resolve a link to the navigation item.
75     */
76    public function __toString(): string
77    {
78        return $this->destination;
79    }
80
81    /**
82     * Get the destination link of the navigation item.
83     *
84     * If the navigation item is an external link, this will return the link as is,
85     * if it's for a route, a resolved relative link will be returned.
86     */
87    public function getDestination(): string
88    {
89        return $this->destination;
90    }
91
92    /**
93     * Get the label of the navigation item.
94     */
95    public function getLabel(): string
96    {
97        return $this->label;
98    }
99
100    /**
101     * Get the priority to determine the order of the navigation item.
102     */
103    public function getPriority(): int
104    {
105        return $this->priority;
106    }
107
108    /**
109     * Get the group identifier of the navigation item, if any.
110     *
111     * For sidebars this is the category key, for navigation menus this is the dropdown key.
112     */
113    public function getGroup(): ?string
114    {
115        return $this->group;
116    }
117
118    /**
119     * Check if the NavItem instance is the current page.
120     */
121    public function isCurrent(): bool
122    {
123        return Hyde::currentRoute()->getLink() === $this->destination;
124    }
125
126    protected static function getRouteGroup(Route $route): ?string
127    {
128        /** @var string|null $group */
129        $group = $route->getPage()->data('navigation.group');
130
131        return static::normalizeGroupKey($group);
132    }
133
134    protected static function normalizeGroupKey(?string $group): ?string
135    {
136        return $group ? Str::slug($group) : null;
137    }
138}