Skip to content

Commit

Permalink
[BUGFIX] Display external pages on all levels of the main menu
Browse files Browse the repository at this point in the history
Sphinx handels it also that way
  • Loading branch information
linawolf committed Mar 4, 2024
1 parent cbfe20e commit 2a37a55
Show file tree
Hide file tree
Showing 14 changed files with 392 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Compiler\NodeTransformers\MenuNodeTransformers;

use phpDocumentor\Guides\Compiler\CompilerContext;
use phpDocumentor\Guides\Nodes\DocumentTree\ExternalEntryNode;
use phpDocumentor\Guides\Nodes\Menu\ExternalMenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\MenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
use phpDocumentor\Guides\Nodes\Menu\TocNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\TitleNode;
use Psr\Log\LoggerInterface;

use function assert;

final class ExternalMenuEntryNodeTransformer extends AbstractMenuEntryNodeTransformer
{
use MenuEntryManagement;
use SubSectionHierarchyHandler;

public function __construct(
LoggerInterface $logger,
) {
parent::__construct($logger);
}

public function supports(Node $node): bool
{
return $node instanceof ExternalMenuEntryNode;
}

/** @return list<MenuEntryNode> */
protected function handleMenuEntry(MenuNode $currentMenu, MenuEntryNode $entryNode, CompilerContext $compilerContext): array
{
assert($entryNode instanceof ExternalMenuEntryNode);

$newEntryNode = new ExternalEntryNode(
$entryNode->getUrl(),
($entryNode->getValue() ?? TitleNode::emptyNode())->toString(),
);

if ($currentMenu instanceof TocNode) {
$this->attachDocumentEntriesToParents([$newEntryNode], $compilerContext, '');
}

return [$entryNode];
}

public function getPriority(): int
{
// After DocumentEntryTransformer
return 4500;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,43 @@

use phpDocumentor\Guides\Compiler\CompilerContext;
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
use phpDocumentor\Guides\Nodes\DocumentTree\ExternalEntryNode;

use function sprintf;
use function str_starts_with;

trait MenuEntryManagement
{
/** @param DocumentEntryNode[] $documentEntriesInTree */
/** @param array<DocumentEntryNode|ExternalEntryNode> $entryNodes */
private function attachDocumentEntriesToParents(
array $documentEntriesInTree,
array $entryNodes,
CompilerContext $compilerContext,
string $currentPath,
): void {
foreach ($documentEntriesInTree as $documentEntryInToc) {
if ($documentEntryInToc->isRoot() || $currentPath === $documentEntryInToc->getFile()) {
// The root page may not be attached to any other
continue;
}
foreach ($entryNodes as $entryNode) {
if ($entryNode instanceof DocumentEntryNode) {
if (($entryNode->isRoot() || $currentPath === $entryNode->getFile())) {
// The root page may not be attached to any other
continue;
}

if ($documentEntryInToc->getParent() !== null && $documentEntryInToc->getParent() !== $compilerContext->getDocumentNode()->getDocumentEntry()) {
$this->logger->warning(sprintf(
'Document %s has been added to parents %s and %s. The `toctree` directive changes the '
. 'position of documents in the document tree. Use the `menu` directive to only display a menu without changing the document tree.',
$documentEntryInToc->getFile(),
$documentEntryInToc->getParent()->getFile(),
$compilerContext->getDocumentNode()->getDocumentEntry()->getFile(),
), $compilerContext->getLoggerInformation());
}
if ($entryNode->getParent() !== null && $entryNode->getParent() !== $compilerContext->getDocumentNode()->getDocumentEntry()) {
$this->logger->warning(sprintf(
'Document %s has been added to parents %s and %s. The `toctree` directive changes the '
. 'position of documents in the document tree. Use the `menu` directive to only display a menu without changing the document tree.',
$entryNode->getFile(),
$entryNode->getParent()->getFile(),
$compilerContext->getDocumentNode()->getDocumentEntry()->getFile(),
), $compilerContext->getLoggerInformation());
}

if ($documentEntryInToc->getParent() !== null) {
continue;
if ($entryNode->getParent() !== null) {
continue;
}
}

$documentEntryInToc->setParent($compilerContext->getDocumentNode()->getDocumentEntry());
$compilerContext->getDocumentNode()->getDocumentEntry()->addChild($documentEntryInToc);
$entryNode->setParent($compilerContext->getDocumentNode()->getDocumentEntry());
$compilerContext->getDocumentNode()->getDocumentEntry()->addChild($entryNode);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
use phpDocumentor\Guides\Compiler\CompilerContext;
use phpDocumentor\Guides\Exception\DocumentEntryNotFound;
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
use phpDocumentor\Guides\Nodes\DocumentTree\ExternalEntryNode;
use phpDocumentor\Guides\Nodes\Menu\ExternalMenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\InternalMenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\MenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\TitleNode;

use function assert;
use function sprintf;
Expand Down Expand Up @@ -74,24 +77,38 @@ private function addSubEntries(
return;
}

foreach ($documentEntry->getChildren() as $subDocumentEntryNode) {
$subMenuEntry = new InternalMenuEntryNode(
$subDocumentEntryNode->getFile(),
$subDocumentEntryNode->getTitle(),
[],
false,
$currentLevel,
'',
self::isInRootline($subDocumentEntryNode, $compilerContext->getDocumentNode()->getDocumentEntry()),
self::isCurrent($subDocumentEntryNode, $compilerContext->getDocumentNode()->getFilePath()),
);
foreach ($documentEntry->getChildren() as $subEntryNode) {
if ($subEntryNode instanceof DocumentEntryNode) {
$subMenuEntry = new InternalMenuEntryNode(
$subEntryNode->getFile(),
$subEntryNode->getTitle(),
[],
false,
$currentLevel,
'',
self::isInRootline($subEntryNode, $compilerContext->getDocumentNode()->getDocumentEntry()),
self::isCurrent($subEntryNode, $compilerContext->getDocumentNode()->getFilePath()),
);

if (!$currentMenu->hasOption('titlesonly') && $maxDepth - $currentLevel + 1 > 1) {
$this->addSubSectionsToMenuEntries($subEntryNode, $subMenuEntry, $maxDepth - $currentLevel + 2);
}

$sectionMenuEntry->addMenuEntry($subMenuEntry);
$this->addSubEntries($currentMenu, $compilerContext, $subMenuEntry, $subEntryNode, $currentLevel + 1, $maxDepth);
continue;
}

if (!$currentMenu->hasOption('titlesonly') && $maxDepth - $currentLevel + 1 > 1) {
$this->addSubSectionsToMenuEntries($subDocumentEntryNode, $subMenuEntry, $maxDepth - $currentLevel + 2);
if (!($subEntryNode instanceof ExternalEntryNode)) {
continue;
}

$subMenuEntry = new ExternalMenuEntryNode(
$subEntryNode->getValue(),
TitleNode::fromString($subEntryNode->getTitle()),
$currentLevel,
);
$sectionMenuEntry->addMenuEntry($subMenuEntry);
$this->addSubEntries($currentMenu, $compilerContext, $subMenuEntry, $subDocumentEntryNode, $currentLevel + 1, $maxDepth);
}
}
}
41 changes: 29 additions & 12 deletions packages/guides/src/Compiler/Passes/GlobalMenuPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
use phpDocumentor\Guides\Compiler\CompilerPass;
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
use phpDocumentor\Guides\Nodes\DocumentTree\ExternalEntryNode;
use phpDocumentor\Guides\Nodes\Menu\ExternalMenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\InternalMenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\MenuEntryNode;
use phpDocumentor\Guides\Nodes\Menu\NavMenuNode;
use phpDocumentor\Guides\Nodes\Menu\TocNode;
use phpDocumentor\Guides\Nodes\TitleNode;
use phpDocumentor\Guides\Settings\SettingsManager;
use Throwable;

Expand Down Expand Up @@ -118,7 +121,7 @@ private function getMenuEntryWithChildren(CompilerContext $compilerContext, Menu
private function addSubEntries(
CompilerContext $compilerContext,
MenuEntryNode $sectionMenuEntry,
DocumentEntryNode $documentEntry,
DocumentEntryNode|ExternalEntryNode $entryNode,
int $currentLevel,
int $maxDepth,
): void {
Expand All @@ -130,17 +133,31 @@ private function addSubEntries(
return;
}

foreach ($documentEntry->getChildren() as $subDocumentEntryNode) {
$subMenuEntry = new InternalMenuEntryNode(
$subDocumentEntryNode->getFile(),
$subDocumentEntryNode->getTitle(),
[],
false,
$currentLevel,
'',
);
$sectionMenuEntry->addMenuEntry($subMenuEntry);
$this->addSubEntries($compilerContext, $subMenuEntry, $subDocumentEntryNode, $currentLevel + 1, $maxDepth);
if (!$entryNode instanceof DocumentEntryNode) {
return;
}

foreach ($entryNode->getChildren() as $subEntryNode) {
if ($subEntryNode instanceof DocumentEntryNode) {
$subMenuEntry = new InternalMenuEntryNode(
$subEntryNode->getFile(),
$subEntryNode->getTitle(),
[],
false,
$currentLevel,
'',
);
$sectionMenuEntry->addMenuEntry($subMenuEntry);
$this->addSubEntries($compilerContext, $subMenuEntry, $subEntryNode, $currentLevel + 1, $maxDepth);
} elseif ($subEntryNode instanceof ExternalEntryNode) {
$subMenuEntry = new ExternalMenuEntryNode(
$subEntryNode->getValue(),
TitleNode::fromString($subEntryNode->getTitle()),
$currentLevel,
);
$sectionMenuEntry->addMenuEntry($subMenuEntry);
$this->addSubEntries($compilerContext, $subMenuEntry, $subEntryNode, $currentLevel + 1, $maxDepth);
}
}
}
}
22 changes: 5 additions & 17 deletions packages/guides/src/Nodes/DocumentTree/DocumentEntryNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@

namespace phpDocumentor\Guides\Nodes\DocumentTree;

use phpDocumentor\Guides\Nodes\AbstractNode;
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\TitleNode;

/** @extends AbstractNode<DocumentNode> */
final class DocumentEntryNode extends AbstractNode
/** @extends EntryNode<DocumentNode> */
final class DocumentEntryNode extends EntryNode
{
/** @var DocumentEntryNode[] */
/** @var array<DocumentEntryNode|ExternalEntryNode> */
private array $entries = [];
/** @var SectionEntryNode[] */
private array $sections = [];
private DocumentEntryNode|null $parent = null;

public function __construct(
private readonly string $file,
Expand All @@ -38,27 +36,17 @@ public function getTitle(): TitleNode
return $this->titleNode;
}

public function addChild(DocumentEntryNode $child): void
public function addChild(DocumentEntryNode|ExternalEntryNode $child): void
{
$this->entries[] = $child;
}

/** @return DocumentEntryNode[] */
/** @return array<DocumentEntryNode|ExternalEntryNode> */
public function getChildren(): array
{
return $this->entries;
}

public function getParent(): DocumentEntryNode|null
{
return $this->parent;
}

public function setParent(DocumentEntryNode|null $parent): void
{
$this->parent = $parent;
}

/** @return SectionEntryNode[] */
public function getSections(): array
{
Expand Down
35 changes: 35 additions & 0 deletions packages/guides/src/Nodes/DocumentTree/EntryNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Nodes\DocumentTree;

use phpDocumentor\Guides\Nodes\AbstractNode;

/**
* @template TValue
* @extends AbstractNode<TValue>
*/
abstract class EntryNode extends AbstractNode
{
private DocumentEntryNode|null $parent = null;

public function getParent(): DocumentEntryNode|null
{
return $this->parent;
}

public function setParent(DocumentEntryNode|null $parent): void
{
$this->parent = $parent;
}
}
28 changes: 28 additions & 0 deletions packages/guides/src/Nodes/DocumentTree/ExternalEntryNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Nodes\DocumentTree;

/** @extends EntryNode<string> */
final class ExternalEntryNode extends EntryNode
{
public function __construct(string $value, public readonly string $title)
{
$this->value = $value;
}

public function getTitle(): string
{
return $this->title;
}
}
5 changes: 2 additions & 3 deletions packages/guides/src/Nodes/DocumentTree/SectionEntryNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@

namespace phpDocumentor\Guides\Nodes\DocumentTree;

use phpDocumentor\Guides\Nodes\AbstractNode;
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\TitleNode;

/** @extends AbstractNode<DocumentNode> */
final class SectionEntryNode extends AbstractNode
/** @extends EntryNode<DocumentNode> */
final class SectionEntryNode extends EntryNode
{
/** @var SectionEntryNode[] */
private array $children = [];
Expand Down
Loading

0 comments on commit 2a37a55

Please sign in to comment.