Skip to content

Commit 288150d

Browse files
linawolfjaapio
authored andcommitted
Move Menu Entry Creation to TocNodeWithDocumentEntryTransformer
1 parent 5e039bc commit 288150d

File tree

8 files changed

+366
-7
lines changed

8 files changed

+366
-7
lines changed

packages/guides/src/Compiler/NodeTransformers/DocumentEntryRegistrationTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function leaveNode(Node $node, CompilerContext $compilerContext): Node|nu
3535
$this->logger->warning('Document has not title', $node->getLoggerInformation());
3636
}
3737

38-
$entry = new DocumentEntryNode($node->getFilePath(), $node->getTitle()??TitleNode::emptyNode());
38+
$entry = new DocumentEntryNode($node->getFilePath(), $node->getTitle() ?? TitleNode::emptyNode());
3939
$compilerContext->getProjectNode()->addDocumentEntry($entry);
4040

4141
return $node->withDocumentEntry($entry);
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Guides\Compiler\NodeTransformers;
6+
7+
use ArrayIterator;
8+
use phpDocumentor\Guides\Compiler\CompilerContext;
9+
use phpDocumentor\Guides\Compiler\NodeTransformer;
10+
use phpDocumentor\Guides\Meta\DocumentReferenceEntry;
11+
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
12+
use phpDocumentor\Guides\Nodes\DocumentTree\Entry as MetaEntry;
13+
use phpDocumentor\Guides\Nodes\DocumentTree\SectionEntryNode;
14+
use phpDocumentor\Guides\Nodes\Menu\MenuEntry;
15+
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
16+
use phpDocumentor\Guides\Nodes\Node;
17+
use Traversable;
18+
19+
use function array_merge;
20+
use function assert;
21+
use function iterator_to_array;
22+
use function ltrim;
23+
24+
/** @implements NodeTransformer<MenuNode> */
25+
final class MenuNodeTransformer implements NodeTransformer
26+
{
27+
public function enterNode(Node $node, CompilerContext $compilerContext): Node
28+
{
29+
$entries = [];
30+
31+
foreach ($node->getFiles() as $file) {
32+
$metaEntry = $compilerContext->getProjectNode()->findDocumentEntry(ltrim($file, '/'));
33+
if (!($metaEntry instanceof DocumentEntryNode)) {
34+
continue;
35+
}
36+
37+
foreach ($this->buildFromDocumentEntry($metaEntry, 1, $node, $compilerContext) as $entry) {
38+
if ($entry->getUrl() === $compilerContext->getDocumentNode()->getFilePath()) {
39+
$entry = $entry->withOptions(array_merge($entry->getOptions(), ['active' => true]));
40+
assert($entry instanceof MenuEntry);
41+
}
42+
43+
$entries[] = $entry;
44+
}
45+
}
46+
47+
return $node->withMenuEntries($entries);
48+
}
49+
50+
public function leaveNode(Node $node, CompilerContext $compilerContext): Node|null
51+
{
52+
return $node;
53+
}
54+
55+
public function supports(Node $node): bool
56+
{
57+
return $node instanceof MenuNode;
58+
}
59+
60+
/** @return iterable<MenuEntry> */
61+
private function buildFromDocumentEntry(DocumentEntryNode $document, int $depth, MenuNode $node, CompilerContext $compilerContext): iterable
62+
{
63+
if ($depth > $node->getDepth()) {
64+
return new ArrayIterator([]);
65+
}
66+
67+
//TocTree's of children are added, unless :titlesonly: is defined. Then only page titles are added, no sections
68+
//Under the section where they are define.
69+
//If Toctree is defined at level 2, and max is 3, only titles of the documents are added to the toctree.
70+
71+
foreach ($document->getChildren() as $child) {
72+
yield from $this->buildLevel($child, $document, $depth, $node, $compilerContext);
73+
}
74+
}
75+
76+
/** @return Traversable<MenuEntry> */
77+
private function buildFromSection(
78+
DocumentEntryNode $document,
79+
SectionEntryNode $entry,
80+
int $depth,
81+
MenuNode $node,
82+
CompilerContext $compilerContext,
83+
): Traversable {
84+
if ($depth > $node->getDepth()) {
85+
return new ArrayIterator([]);
86+
}
87+
88+
foreach ($entry->getChildren() as $child) {
89+
yield from $this->buildLevel($child, $document, $depth, $node, $compilerContext);
90+
}
91+
}
92+
93+
/** @return Traversable<MenuEntry> */
94+
private function buildLevel(
95+
MetaEntry $child,
96+
DocumentEntryNode $document,
97+
int $depth,
98+
MenuNode $node,
99+
CompilerContext $compilerContext,
100+
): Traversable {
101+
if ($child instanceof SectionEntryNode) {
102+
if (!$node->isPageLevelOnly() || $depth === 1) {
103+
yield new MenuEntry(
104+
$document->getFile(),
105+
$child->getTitle(),
106+
iterator_to_array($this->buildFromSection($document, $child, ++$depth, $node, $compilerContext), false),
107+
);
108+
}
109+
}
110+
111+
if (!($child instanceof DocumentReferenceEntry)) {
112+
return;
113+
}
114+
115+
$subDocument = $compilerContext->getProjectNode()->findDocumentEntry($child->getFile());
116+
if (!($subDocument instanceof DocumentEntryNode)) {
117+
return;
118+
}
119+
120+
yield from $this->buildFromDocumentEntry($subDocument, ++$depth, $node, $compilerContext);
121+
}
122+
123+
public function getPriority(): int
124+
{
125+
// After CollectLinkTargetsTransformer
126+
return 4000;
127+
}
128+
}

packages/guides/src/Nodes/DocumentNode.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,17 +252,18 @@ public function getDocumentEntry(): DocumentEntryNode|null
252252

253253
public function withDocumentEntry(DocumentEntryNode $documentEntry): DocumentNode
254254
{
255-
$node = clone($this);
255+
$node = clone$this;
256256
$node->documentEntry = $documentEntry;
257+
257258
return $node;
258259
}
259260

260-
public function getRootSectionEntry(): ?SectionEntryNode
261+
public function getRootSectionEntry(): SectionEntryNode|null
261262
{
262263
return $this->rootSectionEntry;
263264
}
264265

265-
public function setRootSectionEntry(?SectionEntryNode $rootSectionEntry): void
266+
public function setRootSectionEntry(SectionEntryNode|null $rootSectionEntry): void
266267
{
267268
$this->rootSectionEntry = $rootSectionEntry;
268269
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Guides\Nodes\Menu;
6+
7+
use phpDocumentor\Guides\Nodes\AbstractNode;
8+
use phpDocumentor\Guides\Nodes\TitleNode;
9+
10+
/** @extends AbstractNode<TitleNode> */
11+
final class MenuEntry extends AbstractNode
12+
{
13+
/** @param MenuEntry[] $children */
14+
public function __construct(
15+
private readonly string $url,
16+
TitleNode $title,
17+
private readonly array $children = [],
18+
private readonly bool $isDocumentRoot = false,
19+
private readonly int $level = 1,
20+
) {
21+
$this->value = $title;
22+
}
23+
24+
public function getUrl(): string
25+
{
26+
return $this->url;
27+
}
28+
29+
/** @return MenuEntry[] */
30+
public function getChildren(): array
31+
{
32+
return $this->children;
33+
}
34+
35+
/** @return MenuEntry[] */
36+
public function getEntries(): array
37+
{
38+
return $this->children;
39+
}
40+
41+
public function isDocumentRoot(): bool
42+
{
43+
return $this->isDocumentRoot;
44+
}
45+
46+
public function getLevel(): int
47+
{
48+
return $this->level;
49+
}
50+
}

packages/guides/tests/unit/Compiler/NodeTransformers/DocumentEntryRegistrationTransformerTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use phpDocumentor\Guides\Nodes\ProjectNode;
1111
use phpDocumentor\Guides\Nodes\SectionNode;
1212
use phpDocumentor\Guides\Nodes\TitleNode;
13-
use PHPUnit\Framework\MockObject\Invocation;
1413
use PHPUnit\Framework\TestCase;
1514
use Psr\Log\LoggerInterface;
1615

0 commit comments

Comments
 (0)