Passed
Push — master ( 540e27...92adcf )
by Caen
02:51 queued 12s
created

NavigationDataFactory::findGroupFromMatter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 3
c 2
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Framework\Factories;
6
7
use function array_flip;
8
use function array_key_exists;
9
use function array_merge;
10
use function config;
11
use Hyde\Framework\Concerns\InteractsWithFrontMatter;
12
use Hyde\Framework\Factories\Concerns\CoreDataObject;
13
use Hyde\Markdown\Contracts\FrontMatter\SubSchemas\NavigationSchema;
14
use Hyde\Markdown\Models\FrontMatter;
15
use Hyde\Pages\DocumentationPage;
16
use Hyde\Pages\MarkdownPost;
17
use Illuminate\Support\Str;
18
use function in_array;
19
use function is_a;
20
21
/**
22
 * Discover data used for navigation menus and the documentation sidebar.
23
 */
24
class NavigationDataFactory extends Concerns\PageDataFactory implements NavigationSchema
25
{
26
    use InteractsWithFrontMatter;
27
28
    /**
29
     * The front matter properties supported by this factory.
30
     *
31
     * Note that this represents a sub-schema, and is used as part of the page schema.
32
     */
33
    public const SCHEMA = NavigationSchema::NAVIGATION_SCHEMA;
34
35
    protected const FALLBACK_PRIORITY = 999;
36
    protected const CONFIG_OFFSET = 500;
37
38
    protected readonly ?string $label;
39
    protected readonly ?string $group;
40
    protected readonly ?bool $hidden;
41
    protected readonly ?int $priority;
42
    private readonly string $title;
43
    private readonly string $routeKey;
44
    private readonly string $pageClass;
45
    private readonly string $identifier;
46
    private readonly FrontMatter $matter;
47
48
    public function __construct(CoreDataObject $pageData, string $title)
49
    {
50
        $this->matter = $pageData->matter;
0 ignored issues
show
Bug introduced by
The property matter is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
51
        $this->identifier = $pageData->identifier;
0 ignored issues
show
Bug introduced by
The property identifier is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
52
        $this->pageClass = $pageData->pageClass;
0 ignored issues
show
Bug introduced by
The property pageClass is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
53
        $this->routeKey = $pageData->routeKey;
0 ignored issues
show
Bug introduced by
The property routeKey is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
54
        $this->title = $title;
0 ignored issues
show
Bug introduced by
The property title is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
55
56
        $this->label = $this->makeLabel();
0 ignored issues
show
Bug introduced by
The property label is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
57
        $this->group = $this->makeGroup();
0 ignored issues
show
Bug introduced by
The property group is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
58
        $this->hidden = $this->makeHidden();
0 ignored issues
show
Bug introduced by
The property hidden is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
59
        $this->priority = $this->makePriority();
0 ignored issues
show
Bug introduced by
The property priority is declared read-only in Hyde\Framework\Factories\NavigationDataFactory.
Loading history...
60
    }
61
62
    public function toArray(): array
63
    {
64
        return [
0 ignored issues
show
introduced by
The expression return array('label' => ...ty' => $this->priority) returns an array which contains values of type boolean|integer|string which are incompatible with the return type Illuminate\Contracts\Support\TValue mandated by Illuminate\Contracts\Support\Arrayable::toArray().
Loading history...
65
            'label' => $this->label,
66
            'group' => $this->group,
67
            'hidden' => $this->hidden,
68
            'priority' => $this->priority,
69
        ];
70
    }
71
72
    protected function makeLabel(): ?string
73
    {
74
        return $this->matter('navigation.label')
75
            ?? $this->searchForLabelInConfig()
76
            ?? $this->matter('title')
77
            ?? $this->title;
78
    }
79
80
    protected function makeGroup(): ?string
81
    {
82
        if ($this->isInstanceOf(DocumentationPage::class)) {
83
            return $this->getDocumentationPageGroup();
84
        }
85
86
        return null;
87
    }
88
89
    protected function makeHidden(): ?bool
90
    {
91
        if ($this->isInstanceOf(MarkdownPost::class)) {
92
            return true;
93
        }
94
95
        if ($this->matter('navigation.hidden', false)) {
96
            return true;
97
        }
98
99
        if (in_array($this->routeKey, config('hyde.navigation.exclude', ['404']))) {
100
            return true;
101
        }
102
103
        return false;
104
    }
105
106
    protected function makePriority(): ?int
107
    {
108
        if ($this->matter('navigation.priority') !== null) {
109
            return $this->matter('navigation.priority');
110
        }
111
112
        return $this->isInstanceOf(DocumentationPage::class)
113
            ? $this->findPriorityInSidebarConfig(array_flip(config('docs.sidebar_order', []))) ?? self::FALLBACK_PRIORITY
114
            : $this->findPriorityInNavigationConfig(config('hyde.navigation.order', [])) ?? self::FALLBACK_PRIORITY;
115
    }
116
117
    private function findPriorityInNavigationConfig(array $config): ?int
118
    {
119
        return array_key_exists($this->routeKey, $config) ? (int) $config[$this->routeKey] : null;
120
    }
121
122
    private function findPriorityInSidebarConfig(array $config): ?int
123
    {
124
        // Sidebars uses a special syntax where the keys are just the page identifiers in a flat array
125
126
        // Adding 250 makes so that pages with a front matter priority that is lower can be shown first.
127
        // It's lower than the fallback of 500 so that the config ones still come first.
128
        // This is all to make it easier to mix ways of adding priorities.
129
130
        return isset($config[$this->identifier])
131
            ? $config[$this->identifier] + (self::CONFIG_OFFSET)
132
            : null;
133
    }
134
135
    private function getDocumentationPageGroup(): ?string
136
    {
137
        // If the documentation page is in a subdirectory,
138
        return str_contains($this->identifier, '/')
139
            // then we can use that as the category name.
140
            ? Str::before($this->identifier, '/')
141
            // Otherwise, we look in the front matter.
142
            : $this->findGroupFromMatter();
143
    }
144
145
    protected function searchForLabelInConfig(): ?string
146
    {
147
        $labelConfig = array_merge([
148
            'index' => 'Home',
149
            'docs/index' => 'Docs',
150
        ], config('hyde.navigation.labels', []));
151
152
        if (isset($labelConfig[$this->routeKey])) {
153
            return $labelConfig[$this->routeKey];
154
        }
155
156
        return null;
157
    }
158
159
    protected function isInstanceOf(string $class): bool
160
    {
161
        return is_a($this->pageClass, $class, true);
162
    }
163
164
    protected function findGroupFromMatter(): mixed
165
    {
166
        return $this->matter('navigation.group')
167
            ?? $this->matter('navigation.category')
168
            ?? 'other';
169
    }
170
}
171