Skip to content

Commit 4b10c80

Browse files
authored
Merge pull request #916 from phpDocumentor/backport/1.x/pr-910
[1.x] Merge pull request #910 from phpDocumentor/speed-improvement
2 parents 01c5711 + c158f48 commit 4b10c80

File tree

4 files changed

+95
-20
lines changed

4 files changed

+95
-20
lines changed

packages/guides/resources/config/guides.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
use phpDocumentor\Guides\TemplateRenderer;
5555
use phpDocumentor\Guides\Twig\AssetsExtension;
5656
use phpDocumentor\Guides\Twig\EnvironmentBuilder;
57+
use phpDocumentor\Guides\Twig\GlobalMenuExtension;
5758
use phpDocumentor\Guides\Twig\Theme\ThemeManager;
5859
use phpDocumentor\Guides\Twig\TwigTemplateRenderer;
5960
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
@@ -207,6 +208,11 @@
207208
->tag('twig.extension')
208209
->autowire()
209210

211+
->set(GlobalMenuExtension::class)
212+
->arg('$nodeRenderer', service('phpdoc.guides.output_node_renderer'))
213+
->tag('twig.extension')
214+
->autowire()
215+
210216
->set(ThemeManager::class)
211217
->arg('$filesystemLoader', service(FilesystemLoader::class))
212218
->arg(

packages/guides/src/RenderContext.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function getDirName(): string
142142

143143
return $dirname;
144144
}
145-
145+
146146
public function hasCurrentFileName(): bool
147147
{
148148
return $this->currentFileName !== null;

packages/guides/src/Twig/AssetsExtension.php

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@
2121
use phpDocumentor\Guides\Meta\Target;
2222
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
2323
use phpDocumentor\Guides\Nodes\BreadCrumbNode;
24-
use phpDocumentor\Guides\Nodes\CollectionNode;
2524
use phpDocumentor\Guides\Nodes\Node;
2625
use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface;
2726
use phpDocumentor\Guides\RenderContext;
2827
use phpDocumentor\Guides\Renderer\UrlGenerator\UrlGeneratorInterface;
2928
use Psr\Log\LoggerInterface;
3029
use RuntimeException;
3130
use Stringable;
32-
use Throwable;
3331
use Twig\Extension\AbstractExtension;
3432
use Twig\TwigFunction;
3533
use Twig\TwigTest;
@@ -39,13 +37,16 @@
3937

4038
final class AssetsExtension extends AbstractExtension
4139
{
40+
private GlobalMenuExtension $menuExtension;
41+
4242
/** @param NodeRenderer<Node> $nodeRenderer */
4343
public function __construct(
4444
private readonly LoggerInterface $logger,
4545
private readonly NodeRenderer $nodeRenderer,
4646
private readonly DocumentNameResolverInterface $documentNameResolver,
4747
private readonly UrlGeneratorInterface $urlGenerator,
4848
) {
49+
$this->menuExtension = new GlobalMenuExtension($this->nodeRenderer);
4950
}
5051

5152
/** @return TwigFunction[] */
@@ -56,7 +57,7 @@ public function getFunctions(): array
5657
new TwigFunction('renderNode', $this->renderNode(...), ['is_safe' => ['html'], 'needs_context' => true]),
5758
new TwigFunction('renderLink', $this->renderLink(...), ['is_safe' => ['html'], 'needs_context' => true]),
5859
new TwigFunction('renderBreadcrumb', $this->renderBreadcrumb(...), ['is_safe' => ['html'], 'needs_context' => true]),
59-
new TwigFunction('renderMenu', $this->renderMenu(...), ['is_safe' => ['html'], 'needs_context' => true]),
60+
new TwigFunction('renderMenu', $this->renderMenu(...), ['is_safe' => ['html'], 'needs_context' => true, 'deprecated' => true]),
6061
new TwigFunction('renderTarget', $this->renderTarget(...), ['is_safe' => ['html'], 'needs_context' => true]),
6162
];
6263
}
@@ -136,22 +137,7 @@ public function renderBreadcrumb(array $context): string
136137
/** @param array{env: RenderContext} $context */
137138
public function renderMenu(array $context, string $menuType, int $maxMenuCount = 0): string
138139
{
139-
$renderContext = $this->getRenderContext($context);
140-
$globalMenues = $renderContext->getProjectNode()->getGlobalMenues();
141-
$menues = [];
142-
foreach ($globalMenues as $menu) {
143-
$menu = $menu->withOptions(['menu' => $menuType]);
144-
try {
145-
$menu = $menu->withCurrentPath($renderContext->getCurrentFileName());
146-
$menu = $menu->withRootlinePaths($renderContext->getCurrentFileRootline());
147-
} catch (Throwable) {
148-
// do nothing, we are in a context without active menu like single page or functional test
149-
}
150-
151-
$menues[] = $menu;
152-
}
153-
154-
return $this->nodeRenderer->render(new CollectionNode($menues), $renderContext);
140+
return $this->menuExtension->renderMenu($context, $menuType);
155141
}
156142

157143
/** @param array{env: RenderContext} $context */
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Guides\Twig;
15+
16+
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
17+
use phpDocumentor\Guides\Nodes\CollectionNode;
18+
use phpDocumentor\Guides\Nodes\Node;
19+
use phpDocumentor\Guides\RenderContext;
20+
use RuntimeException;
21+
use Throwable;
22+
use Twig\Extension\AbstractExtension;
23+
use Twig\TwigFunction;
24+
25+
final class GlobalMenuExtension extends AbstractExtension
26+
{
27+
/**
28+
* Contains cached menu html for each render context to prevent multiple rendering of the same menu.
29+
*
30+
* @var array<string, string>
31+
*/
32+
private array $menuCache = [];
33+
34+
/** @param NodeRenderer<Node> $nodeRenderer */
35+
public function __construct(
36+
private readonly NodeRenderer $nodeRenderer,
37+
) {
38+
}
39+
40+
/** @return TwigFunction[] */
41+
public function getFunctions(): array
42+
{
43+
return [
44+
new TwigFunction('renderMenu', $this->renderMenu(...), ['is_safe' => ['html'], 'needs_context' => true]),
45+
];
46+
}
47+
48+
/** @param array{env: RenderContext} $context */
49+
public function renderMenu(array $context, string $menuType): string
50+
{
51+
$renderContext = $this->getRenderContext($context);
52+
$globalMenues = $renderContext->getProjectNode()->getGlobalMenues();
53+
if (isset($this->menuCache[$renderContext->getCurrentFileName() . '::' . $menuType])) {
54+
return $this->menuCache[$renderContext->getCurrentFileName() . '::' . $menuType];
55+
}
56+
57+
$menues = [];
58+
foreach ($globalMenues as $menu) {
59+
$menu = $menu->withOptions(['menu' => $menuType]);
60+
try {
61+
$menu = $menu->withCurrentPath($renderContext->getCurrentFileName());
62+
$menu = $menu->withRootlinePaths($renderContext->getCurrentFileRootline());
63+
} catch (Throwable) {
64+
// do nothing, we are in a context without active menu like single page or functional test
65+
}
66+
67+
$menues[] = $menu;
68+
}
69+
70+
return $this->menuCache[$renderContext->getCurrentFileName() . '::' . $menuType] = $this->nodeRenderer->render(new CollectionNode($menues), $renderContext);
71+
}
72+
73+
/** @param array{env: RenderContext} $context */
74+
private function getRenderContext(array $context): RenderContext
75+
{
76+
$renderContext = $context['env'] ?? null;
77+
if (!$renderContext instanceof RenderContext) {
78+
throw new RuntimeException('Render context must be set in the twig global state to render nodes');
79+
}
80+
81+
return $renderContext;
82+
}
83+
}

0 commit comments

Comments
 (0)