Skip to content

Commit 0adfe93

Browse files
authored
Merge pull request #1128 from phpDocumentor/task/automenu2
[FEATURE] Support automatically created multi-level menus
2 parents 5ad233a + f030169 commit 0adfe93

File tree

24 files changed

+711
-69
lines changed

24 files changed

+711
-69
lines changed

packages/guides/src/Compiler/Passes/AutomaticMenuPass.php

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,20 @@
1717
use phpDocumentor\Guides\Compiler\CompilerPass;
1818
use phpDocumentor\Guides\Nodes\DocumentNode;
1919
use phpDocumentor\Guides\Settings\SettingsManager;
20+
use Psr\Log\LoggerInterface;
21+
22+
use function array_pop;
23+
use function count;
24+
use function explode;
25+
use function implode;
26+
use function in_array;
27+
use function sprintf;
2028

2129
final class AutomaticMenuPass implements CompilerPass
2230
{
2331
public function __construct(
2432
private readonly SettingsManager $settingsManager,
33+
private readonly LoggerInterface|null $logger = null,
2534
) {
2635
}
2736

@@ -43,6 +52,7 @@ public function run(array $documents, CompilerContextInterface $compilerContext)
4352

4453
$projectNode = $compilerContext->getProjectNode();
4554
$rootDocumentEntry = $projectNode->getRootDocumentEntry();
55+
$indexNames = explode(',', $this->settingsManager->getProjectSettings()->getIndexName());
4656
foreach ($documents as $documentNode) {
4757
if ($documentNode->isOrphan()) {
4858
// Do not add orphans to the automatic menu
@@ -53,9 +63,48 @@ public function run(array $documents, CompilerContextInterface $compilerContext)
5363
continue;
5464
}
5565

56-
$documentEntry = $projectNode->getDocumentEntry($documentNode->getFilePath());
57-
$documentEntry->setParent($rootDocumentEntry);
58-
$rootDocumentEntry->addChild($documentEntry);
66+
$filePath = $documentNode->getFilePath();
67+
$pathParts = explode('/', $filePath);
68+
$documentEntry = $projectNode->getDocumentEntry($filePath);
69+
if (count($pathParts) === 1 || count($pathParts) === 2 && in_array($pathParts[1], $indexNames, true)) {
70+
$documentEntry->setParent($rootDocumentEntry);
71+
$rootDocumentEntry->addChild($documentEntry);
72+
continue;
73+
}
74+
75+
$fileName = array_pop($pathParts);
76+
$path = implode('/', $pathParts);
77+
if (in_array($fileName, $indexNames, true)) {
78+
array_pop($pathParts);
79+
$path = implode('/', $pathParts);
80+
}
81+
82+
$parentFound = false;
83+
foreach ($indexNames as $indexName) {
84+
$indexFile = $path . '/' . $indexName;
85+
$parentEntry = $projectNode->findDocumentEntry($indexFile);
86+
if ($parentEntry === null) {
87+
continue;
88+
}
89+
90+
$documentEntry->setParent($parentEntry);
91+
$parentEntry->addChild($documentEntry);
92+
$parentFound = true;
93+
break;
94+
}
95+
96+
if ($parentFound) {
97+
continue;
98+
}
99+
100+
$parentEntry = $projectNode->findDocumentEntry($path);
101+
if ($parentEntry === null) {
102+
$this->logger?->warning(sprintf('No parent found for file "%s/%s" attaching it to the document root instead. ', $path, $fileName));
103+
continue;
104+
}
105+
106+
$documentEntry->setParent($parentEntry);
107+
$parentEntry->addChild($documentEntry);
59108
}
60109

61110
return $documents;

packages/guides/src/Compiler/Passes/GlobalMenuPass.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,23 @@ public function run(array $documents, CompilerContextInterface $compilerContext)
9090

9191
private function getNavMenuNodeFromDocumentEntries(CompilerContextInterface $compilerContext): NavMenuNode
9292
{
93-
$menuEntries = [];
9493
$rootDocumentEntry = $compilerContext->getProjectNode()->getRootDocumentEntry();
94+
$menuEntries = $this->getMenuEntriesFromDocumentEntries($rootDocumentEntry);
95+
96+
return new NavMenuNode($menuEntries);
97+
}
98+
99+
/** @return InternalMenuEntryNode[] */
100+
public function getMenuEntriesFromDocumentEntries(DocumentEntryNode $rootDocumentEntry): array
101+
{
102+
$menuEntries = [];
95103
foreach ($rootDocumentEntry->getChildren() as $documentEntryNode) {
96-
$newMenuEntry = new InternalMenuEntryNode($documentEntryNode->getFile(), $documentEntryNode->getTitle(), [], false, 1);
104+
$children = $this->getMenuEntriesFromDocumentEntries($documentEntryNode);
105+
$newMenuEntry = new InternalMenuEntryNode($documentEntryNode->getFile(), $documentEntryNode->getTitle(), $children, false, 1);
97106
$menuEntries[] = $newMenuEntry;
98107
}
99108

100-
return new NavMenuNode($menuEntries);
109+
return $menuEntries;
101110
}
102111

103112
private function getNavMenuNodefromTocNode(CompilerContextInterface $compilerContext, TocNode $tocNode, string|null $menuType = null): NavMenuNode

tests/Integration/tests-full/automatic_menu/automatic-multilevel-menu/expected/index.html

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@
5252
<li>
5353
<a href="someDirectory/anotherDirectory/index.html"
5454
class="nav-link">Another Page</a>
55-
<ul class="level-2">
55+
<ul class="level-1">
5656
<li>
5757
<a href="someDirectory/anotherDirectory/yetAnotherDirectory/index.html"
5858
class="nav-link">Yet Another Page</a>
59-
<ul class="level-3">
59+
<ul class="level-1">
6060
<li>
6161
<a href="someDirectory/anotherDirectory/yetAnotherDirectory/andYetAnotherDirectory/index.html"
6262
class="nav-link">And Yet Another Page</a>
@@ -88,33 +88,6 @@ <h1>Document Title</h1>
8888

8989
<p>Lorem Ipsum Dolor.</p>
9090

91-
<div class="toc">
92-
<ul class="menu-level">
93-
<li class="toc-item">
94-
<a href="someDirectory/index.html#some-page">Some Page</a>
95-
<ul class="menu-level-1">
96-
<li class="toc-item">
97-
<a href="someDirectory/anotherDirectory/index.html#another-page">Another Page</a>
98-
<ul class="menu-level-2">
99-
<li class="toc-item">
100-
<a href="someDirectory/anotherDirectory/yetAnotherDirectory/index.html#yet-another-page">Yet Another Page</a>
101-
<ul class="menu-level-3">
102-
<li class="toc-item">
103-
<a href="someDirectory/anotherDirectory/yetAnotherDirectory/andYetAnotherDirectory/index.html#and-yet-another-page">And Yet Another Page</a>
104-
105-
106-
</li>
107-
</ul>
108-
109-
</li>
110-
</ul>
111-
112-
</li>
113-
</ul>
114-
115-
</li>
116-
</ul>
117-
</div>
11891
</div>
11992
<!-- content end -->
12093
</div>

tests/Integration/tests-full/automatic_menu/automatic-multilevel-menu/input/skip

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<!DOCTYPE html>
2+
<html class="no-js" lang="en">
3+
<head>
4+
<title>Dir 2 Title</title>
5+
<!-- Required meta tags -->
6+
<meta charset="utf-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
9+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
10+
</head>
11+
<body>
12+
<header class="">
13+
14+
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
15+
<div class="container">
16+
17+
<a class="navbar-brand" href="#">Navbar</a>
18+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
19+
<span class="navbar-toggler-icon"></span>
20+
</button>
21+
<div class="collapse navbar-collapse" id="navbarSupportedContent">
22+
23+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
24+
<li class="nav-item">
25+
<a href="../anotherPage.html" class="nav-link">
26+
Another Page
27+
</a>
28+
</li><li class="nav-item">
29+
<a href="../dir1/index.html" class="nav-link">
30+
Dir 1 Title
31+
</a>
32+
</li><li class="nav-item">
33+
<a href="#" class="nav-link current active" aria-current="page">
34+
Dir 2 Title
35+
</a>
36+
</li>
37+
<ul class="level-">
38+
<li class="nav-item">
39+
<a href="../anotherPage.html"
40+
class="nav-link">Another Page</a>
41+
</li>
42+
<li class="nav-item">
43+
<a href="../dir1/index.html"
44+
class="nav-link">Dir 1 Title</a>
45+
</li>
46+
<li class="nav-item">
47+
<a href="#"
48+
class="nav-link current active" aria-current="page">Dir 2 Title</a>
49+
</li>
50+
<li class="nav-item">
51+
<a href="../somePage.html"
52+
class="nav-link">Some Page</a>
53+
</li>
54+
<li class="nav-item">
55+
<a href="../yetAnotherPage.html"
56+
class="nav-link">Yet Another Page</a>
57+
</li>
58+
</ul>
59+
<li class="nav-item">
60+
<a href="../somePage.html" class="nav-link">
61+
Some Page
62+
</a>
63+
</li><li class="nav-item">
64+
<a href="../yetAnotherPage.html" class="nav-link">
65+
Yet Another Page
66+
</a>
67+
</li></ul>
68+
69+
</div>
70+
</div>
71+
</nav>
72+
</header>
73+
<main id="main-content">
74+
<div class="container">
75+
<div class="container">
76+
<div class="row">
77+
<div class="col-lg-3">
78+
<nav class="nav flex-column">
79+
<ul class="menu-level-main">
80+
<li>
81+
<a href="../anotherPage.html"
82+
class="nav-link">Another Page</a>
83+
</li>
84+
<li>
85+
<a href="../dir1/index.html"
86+
class="nav-link">Dir 1 Title</a>
87+
</li>
88+
<li>
89+
<a href="#"
90+
class="nav-link current active" aria-current="page">Dir 2 Title</a>
91+
<ul class="level-1">
92+
<li>
93+
<a href="somePage.html"
94+
class="nav-link">Some Page in dir 2</a>
95+
</li>
96+
<li>
97+
<a href="subdir1/index.html"
98+
class="nav-link">Subdir 1 Title</a>
99+
</li>
100+
<li>
101+
<a href="subdir2/index.html"
102+
class="nav-link">Subdir 2 Title</a>
103+
<ul class="level-1">
104+
<li>
105+
<a href="subdir2/somePage.html"
106+
class="nav-link">Some Page in dir 2</a>
107+
</li>
108+
<li>
109+
<a href="subdir2/subsubdir1/index.html"
110+
class="nav-link">Subsubdir 1 Title</a>
111+
</li>
112+
</ul>
113+
114+
</li>
115+
<li>
116+
<a href="yetAnotherPage.html"
117+
class="nav-link">Yet Another Page</a>
118+
</li>
119+
</ul>
120+
121+
</li>
122+
<li>
123+
<a href="../somePage.html"
124+
class="nav-link">Some Page</a>
125+
</li>
126+
<li>
127+
<a href="../yetAnotherPage.html"
128+
class="nav-link">Yet Another Page</a>
129+
</li>
130+
</ul>
131+
</nav>
132+
133+
</div>
134+
<div class="col-lg-9">
135+
136+
<nav aria-label="breadcrumb">
137+
<ol class="breadcrumb">
138+
<li class="breadcrumb-item"><a href="../index.html">Document Title</a></li>
139+
<li class="breadcrumb-item"><a href="#">Dir 2 Title</a></li>
140+
</ol>
141+
</nav>
142+
<!-- content start -->
143+
<div class="section" id="dir-2-title">
144+
<h1>Dir 2 Title</h1>
145+
146+
<p>Lorem Ipsum Dolor.</p>
147+
148+
</div>
149+
<!-- content end -->
150+
</div>
151+
</div>
152+
</div>
153+
</div>
154+
</main>
155+
156+
<!-- Optional JavaScript; choose one of the two! -->
157+
158+
<!-- Option 1: Bootstrap Bundle with Popper -->
159+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
160+
161+
<!-- Option 2: Separate Popper and Bootstrap JS -->
162+
<!--
163+
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
164+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
165+
-->
166+
</body>
167+
</html>

0 commit comments

Comments
 (0)