Passed
Push — master ( 943704...e7a8ff )
by Caen
03:00 queued 12s
created

NavigationMenu::canBeInDropdown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Framework\Features\Navigation;
6
7
use BadMethodCallException;
8
use function config;
9
use Hyde\Foundation\Facades\Router;
10
use Hyde\Pages\DocumentationPage;
11
use Hyde\Pages\MarkdownPost;
12
use Hyde\Support\Models\Route;
13
use Illuminate\Support\Collection;
14
use function in_array;
15
16
/**
17
 * @see \Hyde\Framework\Testing\Feature\NavigationMenuTest
18
 * @phpstan-consistent-constructor
19
 */
20
class NavigationMenu
21
{
22
    public Route $currentRoute;
23
24
    public Collection $items;
25
26
    /** @var array<string, array<NavItem>> */
27
    protected array $dropdowns;
28
29
    public function __construct()
30
    {
31
        $this->items = new Collection();
32
    }
33
34
    public static function create(): static
35
    {
36
        return (new static())->generate()->filter()->sort();
37
    }
38
39
    /** @return $this */
40
    public function generate(): static
41
    {
42
        Router::each(function (Route $route): void {
0 ignored issues
show
Bug introduced by
The method each() does not exist on Hyde\Foundation\Facades\Router. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
        Router::/** @scrutinizer ignore-call */ 
43
                each(function (Route $route): void {
Loading history...
43
            $this->items->push(NavItem::fromRoute($route));
44
        });
45
46
        collect(config('hyde.navigation.custom', []))->each(function (NavItem $item): void {
47
            $this->items->push($item);
48
        });
49
50
        if ($this->dropdownsEnabled()) {
51
            $this->dropdowns = $this->makeDropdowns();
52
        }
53
54
        return $this;
55
    }
56
57
    /** @return $this */
58
    public function filter(): static
59
    {
60
        $this->items = $this->filterHiddenItems();
61
        $this->items = $this->filterDuplicateItems();
62
63
        if ($this->dropdownsEnabled()) {
64
            $this->items = $this->filterDropdownItems();
65
        }
66
67
        return $this;
68
    }
69
70
    /** @return $this */
71
    public function sort(): static
72
    {
73
        $this->items = $this->items->sortBy('priority')->values();
74
75
        return $this;
76
    }
77
78
    protected function filterHiddenItems(): Collection
79
    {
80
        return $this->items->reject(function (NavItem $item): bool {
81
            return $item->hidden || $this->filterDocumentationPage($item);
82
        })->values();
83
    }
84
85
    protected function filterDuplicateItems(): Collection
86
    {
87
        return $this->items->unique(function (NavItem $item): string {
88
            return $item->resolveLink();
89
        });
90
    }
91
92
    protected function filterDropdownItems(): Collection
93
    {
94
        $dropdownItems = collect($this->getDropdowns())->flatten()->toArray();
0 ignored issues
show
Bug introduced by
$this->getDropdowns() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

94
        $dropdownItems = collect(/** @scrutinizer ignore-type */ $this->getDropdowns())->flatten()->toArray();
Loading history...
95
96
        return $this->items->reject(function (NavItem $item) use ($dropdownItems): bool {
97
            return in_array($item, $dropdownItems);
98
        });
99
    }
100
101
    protected function filterDocumentationPage(NavItem $item): bool
102
    {
103
        return isset($item->route)
104
            && $item->route->getPage() instanceof DocumentationPage
105
            && $item->route->getRouteKey() !== 'docs/index';
106
    }
107
108
    public function hasDropdowns(): bool
109
    {
110
        if (! $this->dropdownsEnabled()) {
111
            return false;
112
        }
113
114
        return count($this->getDropdowns()) >= 1;
115
    }
116
117
    /** @return array<string, array<NavItem>> */
118
    public function getDropdowns(): array
119
    {
120
        if (! $this->dropdownsEnabled()) {
121
            throw new BadMethodCallException('Dropdowns are not enabled. Enable it by setting `hyde.navigation.subdirectories` to `dropdown`.');
122
        }
123
124
        return $this->dropdowns;
125
    }
126
127
    protected static function canBeInDropdown(NavItem $item): bool
128
    {
129
        return ($item->getGroup() !== null) && ! in_array($item->route->getPageClass(), [DocumentationPage::class, MarkdownPost::class]);
130
    }
131
132
    protected static function dropdownsEnabled(): bool
133
    {
134
        return config('hyde.navigation.subdirectories', 'hidden') === 'dropdown';
135
    }
136
137
    protected function makeDropdowns(): array
138
    {
139
        $dropdowns = [];
140
141
        /** @var \Hyde\Framework\Features\Navigation\NavItem $item */
142
        foreach ($this->items as $item) {
143
            if (! $this->canBeInDropdown($item)) {
144
                continue;
145
            }
146
147
            $dropdowns[$item->getGroup()][] = $item;
148
        }
149
150
        return $dropdowns;
151
    }
152
}
153