Skip to content

Commit e3beab8

Browse files
committed
Latte: added {linkBase}
1 parent 189d55e commit e3beab8

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

src/Application/LinkGenerator.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,4 +295,13 @@ private function isDeprecated(?UI\Presenter $presenter, \ReflectionClass|\Reflec
295295
return $presenter?->invalidLinkMode
296296
&& (UI\ComponentReflection::parseAnnotation($reflection, 'deprecated') || $reflection->getAttributes(Attributes\Deprecated::class));
297297
}
298+
299+
300+
/** @internal */
301+
public static function applyBase(string $link, string $base): string
302+
{
303+
return str_contains($link, ':') && $link[0] !== ':'
304+
? ":$base:$link"
305+
: $link;
306+
}
298307
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Bridges\ApplicationLatte\Nodes;
11+
12+
use Latte\CompileException;
13+
use Latte\Compiler\Node;
14+
use Latte\Compiler\NodeHelpers;
15+
use Latte\Compiler\Nodes\Php\Expression\AuxiliaryNode;
16+
use Latte\Compiler\Nodes\Php\ExpressionNode;
17+
use Latte\Compiler\Nodes\Php\Scalar\StringNode;
18+
use Latte\Compiler\Nodes\StatementNode;
19+
use Latte\Compiler\Nodes\TemplateNode;
20+
use Latte\Compiler\NodeTraverser;
21+
use Latte\Compiler\PrintContext;
22+
use Latte\Compiler\Tag;
23+
use Nette\Application\LinkGenerator;
24+
25+
26+
/**
27+
* {linkBase module}
28+
*/
29+
class LinkBaseNode extends StatementNode
30+
{
31+
public ExpressionNode $base;
32+
33+
34+
public static function create(Tag $tag): static
35+
{
36+
$tag->expectArguments();
37+
if (!$tag->isInHead()) {
38+
throw new CompileException("{{$tag->name}} must be placed in template head.", $tag->position);
39+
}
40+
41+
$node = new static;
42+
$node->base = $tag->parser->parseUnquotedStringOrExpression();
43+
return $node;
44+
}
45+
46+
47+
public function print(PrintContext $context): string
48+
{
49+
return '';
50+
}
51+
52+
53+
public function &getIterator(): \Generator
54+
{
55+
yield $this->base;
56+
}
57+
58+
59+
public static function applyLinkBasePass(TemplateNode $node): void
60+
{
61+
$base = NodeHelpers::findFirst($node, fn(Node $node) => $node instanceof self)?->base;
62+
if ($base === null) {
63+
return;
64+
}
65+
66+
(new NodeTraverser)->traverse($node, function (Node $link) use ($base) {
67+
if ($link instanceof LinkNode) {
68+
if ($link->destination instanceof StringNode && $base instanceof StringNode) {
69+
$link->destination->value = LinkGenerator::applyBase($link->destination->value, $base->value);
70+
} else {
71+
$origDestination = $link->destination;
72+
$link->destination = new AuxiliaryNode(
73+
fn(PrintContext $context) => $context->format(
74+
LinkGenerator::class . '::applyBase(%node, %node)',
75+
$origDestination,
76+
$base,
77+
),
78+
);
79+
}
80+
}
81+
});
82+
}
83+
}

src/Bridges/ApplicationLatte/UIExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public function getTags(): array
7979
'control' => Nodes\ControlNode::create(...),
8080
'plink' => Nodes\LinkNode::create(...),
8181
'link' => Nodes\LinkNode::create(...),
82+
'linkBase' => Nodes\LinkBaseNode::create(...),
8283
'ifCurrent' => Nodes\IfCurrentNode::create(...),
8384
'templatePrint' => Nodes\TemplatePrintNode::create(...),
8485
'snippet' => Nodes\SnippetNode::create(...),
@@ -93,6 +94,7 @@ public function getPasses(): array
9394
{
9495
return [
9596
'snippetRendering' => $this->snippetRenderingPass(...),
97+
'applyLinkBase' => [Nodes\LinkBaseNode::class, 'applyLinkBasePass'],
9698
];
9799
}
98100

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/**
4+
* Test: {linkBase ...}
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Tester\Assert;
10+
11+
require __DIR__ . '/../bootstrap.php';
12+
13+
if (version_compare(Latte\Engine::VERSION, '3', '<')) {
14+
Tester\Environment::skip('Test for Latte 3');
15+
}
16+
17+
18+
$latte = new Latte\Engine;
19+
$latte->setLoader(new Latte\Loaders\StringLoader);
20+
$latte->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension(null));
21+
22+
23+
Assert::contains(
24+
'$this->global->uiControl->link(\'foo\')',
25+
$latte->compile('{linkBase Base}{link foo}'),
26+
);
27+
Assert::contains(
28+
'$this->global->uiControl->link(\':Base:Foo:\')',
29+
$latte->compile('{linkBase Base}{link Foo:}'),
30+
);
31+
Assert::contains(
32+
'$this->global->uiControl->link(\':Foo:\')',
33+
$latte->compile('{linkBase Base}{link :Foo:}'),
34+
);
35+
36+
37+
// dynamic
38+
Assert::contains(
39+
'$this->global->uiControl->link(Nette\Application\LinkGenerator::applyBase($link, \'Base\'))',
40+
$latte->compile('{linkBase Base}{link $link}'),
41+
);
42+
Assert::contains(
43+
'$this->global->uiControl->link(Nette\Application\LinkGenerator::applyBase(\'foo\', $base))',
44+
$latte->compile('{linkBase $base}{link foo}'),
45+
);

0 commit comments

Comments
 (0)