diff --git a/packages/guides/src/Nodes/ProjectNode.php b/packages/guides/src/Nodes/ProjectNode.php index 7690c434c..2afce43e2 100644 --- a/packages/guides/src/Nodes/ProjectNode.php +++ b/packages/guides/src/Nodes/ProjectNode.php @@ -47,7 +47,10 @@ final class ProjectNode extends CompoundNode /** @var array> */ private array $internalLinkTargets = []; - /** @var DocumentEntryNode[] */ + /** Cached root document entry for O(1) lookup */ + private DocumentEntryNode|null $rootDocumentEntry = null; + + /** @var array */ private array $documentEntries = []; private DateTimeImmutable $lastRendered; @@ -182,6 +185,11 @@ public function getAllInternalTargets(): array public function addDocumentEntry(DocumentEntryNode $documentEntry): void { + // Cache root for O(1) lookup + if ($documentEntry->isRoot()) { + $this->rootDocumentEntry = $documentEntry; + } + $this->documentEntries[$documentEntry->getFile()] = $documentEntry; } @@ -193,10 +201,8 @@ public function getAllDocumentEntries(): array public function getRootDocumentEntry(): DocumentEntryNode { - foreach ($this->documentEntries as $documentEntry) { - if ($documentEntry->isRoot()) { - return $documentEntry; - } + if ($this->rootDocumentEntry !== null) { + return $this->rootDocumentEntry; } throw new Exception('No root document entry was found'); @@ -205,10 +211,9 @@ public function getRootDocumentEntry(): DocumentEntryNode /** @throws DocumentEntryNotFound */ public function getDocumentEntry(string $file): DocumentEntryNode { - foreach ($this->documentEntries as $documentEntry) { - if ($documentEntry->getFile() === $file) { - return $documentEntry; - } + // O(1) lookup by file path + if (isset($this->documentEntries[$file])) { + return $this->documentEntries[$file]; } throw new DocumentEntryNotFound('No document Entry found for file ' . $file); @@ -217,7 +222,12 @@ public function getDocumentEntry(string $file): DocumentEntryNode /** @param DocumentEntryNode[] $documentEntries */ public function setDocumentEntries(array $documentEntries): void { - $this->documentEntries = $documentEntries; + $this->documentEntries = []; + $this->rootDocumentEntry = null; + + foreach ($documentEntries as $entry) { + $this->addDocumentEntry($entry); + } } public function findDocumentEntry(string $filePath): DocumentEntryNode|null @@ -228,6 +238,7 @@ public function findDocumentEntry(string $filePath): DocumentEntryNode|null public function reset(): void { $this->documentEntries = []; + $this->rootDocumentEntry = null; } public function getLastRendered(): DateTimeImmutable diff --git a/tests/Functional/FunctionalTest.php b/tests/Functional/FunctionalTest.php index f0e5d53df..bcac5797f 100644 --- a/tests/Functional/FunctionalTest.php +++ b/tests/Functional/FunctionalTest.php @@ -25,10 +25,8 @@ use phpDocumentor\Guides\Compiler\Compiler; use phpDocumentor\Guides\Compiler\CompilerContext; use phpDocumentor\Guides\NodeRenderers\NodeRenderer; -use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode; use phpDocumentor\Guides\Nodes\Node; use phpDocumentor\Guides\Nodes\ProjectNode; -use phpDocumentor\Guides\Nodes\TitleNode; use phpDocumentor\Guides\Parser; use phpDocumentor\Guides\RenderContext; use phpDocumentor\Guides\Settings\ProjectSettings; @@ -110,13 +108,11 @@ public function testFunctional( $parser = $this->getContainer()->get(Parser::class); assert($parser instanceof Parser); - $document = $parser->parse($rst); - $documentEntry = new DocumentEntryNode($document->getFilePath(), $document->getTitle() ?? TitleNode::fromString(''), true); + $document = $parser->parse($rst)->withIsRoot(true); $compiler = $this->getContainer()->get(Compiler::class); assert($compiler instanceof Compiler); $projectNode = new ProjectNode(); - $projectNode->setDocumentEntries([$documentEntry]); $compiler->run([$document], new CompilerContext($projectNode)); $inputFilesystem = FlySystemAdapter::createFromFileSystem(new Filesystem(new InMemoryFilesystemAdapter()));