Skip to content

Commit 6171014

Browse files
committed
ExpressionAttributeNode: utilizes HtmlHelpers/XmlHelpers::format*Attribute() functions
1 parent 565f293 commit 6171014

File tree

11 files changed

+193
-52
lines changed

11 files changed

+193
-52
lines changed

src/Latte/Compiler/Nodes/Html/ExpressionAttributeNode.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Latte\Compiler\Nodes\Php\ModifierNode;
1515
use Latte\Compiler\Position;
1616
use Latte\Compiler\PrintContext;
17+
use Latte\ContentType;
18+
use Latte\Runtime as LR;
1719

1820

1921
class ExpressionAttributeNode extends AreaNode
@@ -30,17 +32,17 @@ public function __construct(
3032

3133
public function print(PrintContext $context): string
3234
{
33-
$escaper = $context->beginEscape();
34-
$escaper->enterHtmlAttribute();
35-
$res = $context->format(
36-
'echo %dump; echo %modify(%node) %line; echo \'"\';',
37-
$this->indentation . $this->name . '="',
35+
$this->modifier->escape = false;
36+
return $context->format(
37+
'echo %raw(%dump, %modify(%node)) %line;',
38+
$context->getEscaper()->getContentType() === ContentType::Html
39+
? 'LR\HtmlHelpers::format' . ucfirst(LR\HtmlHelpers::classifyAttributeType($this->name)) . 'Attribute'
40+
: 'LR\XmlHelpers::formatCommonAttribute',
41+
$this->indentation . $this->name,
3842
$this->modifier,
3943
$this->value,
4044
$this->value->position,
4145
);
42-
$context->restoreEscape();
43-
return $res;
4446
}
4547

4648

src/Latte/Runtime/HtmlHelpers.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ public static function formatAttribute(string $name, mixed $value): ?string
190190
}
191191

192192

193+
public static function classifyAttributeType(string $name): string
194+
{
195+
$name = strtolower($name);
196+
return match (true) {
197+
default => 'common',
198+
};
199+
}
200+
201+
202+
/**
203+
* Formats common HTML attribute.
204+
*/
205+
public static function formatCommonAttribute(string $namePart, mixed $value): string
206+
{
207+
return $namePart . '="' . self::escapeAttr($value) . '"';
208+
}
209+
210+
193211
/**
194212
* Checks if the given tag name represents a void (empty) HTML element.
195213
*/

src/Latte/Runtime/XmlHelpers.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ public static function formatAttribute(string $name, mixed $value): ?string
9696
}
9797

9898

99+
public static function formatCommonAttribute(string $namePart, mixed $value): string
100+
{
101+
return $namePart . '="' . self::escapeAttr($value) . '"';
102+
}
103+
104+
99105
/**
100106
* Checks that the HTML tag name can be changed.
101107
*/

tests/common/Safe.url.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Assert::match(
7474

7575

7676
Assert::contains(
77-
'LR\HtmlHelpers::escapeAttr(($this->filters->checkUrl)(($this->filters->upper)($url1)))',
77+
'LR\HtmlHelpers::formatCommonAttribute(\' href\', ($this->filters->checkUrl)(($this->filters->upper)($url1)))',
7878
$latte->compile('<a href="{$url1|upper}"></a>'),
7979
);
8080

tests/common/expected/Compiler.unquoted.attrs.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ public function main(array $ʟ_args): void
88
%A%
99
echo '<span title=hello></span>
1010
11-
<span title="';
12-
echo LR\HtmlHelpers::escapeAttr($x) /* line %d%:%d% */;
13-
echo '" class="';
14-
echo LR\HtmlHelpers::escapeAttr($x) /* line %d%:%d% */;
15-
echo '"></span>
11+
<span';
12+
echo LR\HtmlHelpers::formatCommonAttribute(' title', $x) /* line %d%:%d% */;
13+
echo LR\HtmlHelpers::formatCommonAttribute(' class', $x) /* line %d%:%d% */;
14+
echo '></span>
1615
17-
<span title="';
18-
echo LR\HtmlHelpers::escapeAttr($x) /* line %d%:%d% */;
19-
echo '" ';
16+
<span';
17+
echo LR\HtmlHelpers::formatCommonAttribute(' title', $x) /* line %d%:%d% */;
18+
echo ' ';
2019
echo LR\HtmlHelpers::escapeTag($x) /* line %d%:%d% */;
2120
echo '></span>
2221
@@ -38,9 +37,9 @@ public function main(array $ʟ_args): void
3837
echo LR\HtmlHelpers::escapeAttr($x) /* line %d%:%d% */;
3938
echo 'd"></span>
4039
41-
<span onclick="';
42-
echo LR\HtmlHelpers::escapeAttr($x) /* line %d%:%d% */;
43-
echo '" ';
40+
<span';
41+
echo LR\HtmlHelpers::formatCommonAttribute(' onclick', $x) /* line %d%:%d% */;
42+
echo ' ';
4443
echo LR\HtmlHelpers::escapeTag($x) /* line %d%:%d% */;
4544
echo '></span>
4645

tests/common/expected/contentType.xml.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ public function main(array $ʟ_args): void
7171
echo '"\'
7272
style="color:';
7373
echo LR\XmlHelpers::escapeAttr($id) /* line %d%:%d% */;
74-
echo ';\'"
75-
alt="';
76-
echo LR\XmlHelpers::escapeAttr($el) /* line %d%:%d% */;
77-
echo '"
74+
echo ';\'"';
75+
echo LR\XmlHelpers::formatCommonAttribute('
76+
alt', $el) /* line %d%:%d% */;
77+
echo '
7878
onfocus="alert(';
7979
echo LR\XmlHelpers::escapeAttr($el) /* line %d%:%d% */;
8080
echo ')"
@@ -119,13 +119,13 @@ public function main(array $ʟ_args): void
119119
}
120120
echo '"> </p>
121121
122-
<p val="';
123-
echo LR\XmlHelpers::escapeAttr($xss) /* line %d%:%d% */;
124-
echo '" > </p>
122+
<p';
123+
echo LR\XmlHelpers::formatCommonAttribute(' val', $xss) /* line %d%:%d% */;
124+
echo ' > </p>
125125
126-
<p onclick="';
127-
echo LR\XmlHelpers::escapeAttr($xss) /* line %d%:%d% */;
128-
echo '"> </p>
126+
<p';
127+
echo LR\XmlHelpers::formatCommonAttribute(' onclick', $xss) /* line %d%:%d% */;
128+
echo '> </p>
129129
';
130130
}
131131

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Latte\Runtime\HtmlHelpers;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
class Str
12+
{
13+
public function __toString()
14+
{
15+
return 'one&<br>';
16+
}
17+
}
18+
19+
20+
// text
21+
Assert::same(
22+
'title="Hello &amp; Welcome"',
23+
HtmlHelpers::formatCommonAttribute('title', 'Hello & Welcome'),
24+
);
25+
Assert::same(
26+
'title="&quot;Hello&quot; &amp; &apos;Welcome&apos;"',
27+
HtmlHelpers::formatCommonAttribute('title', '"Hello" & \'Welcome\''),
28+
);
29+
Assert::same('title=""', HtmlHelpers::formatCommonAttribute('title', ''));
30+
Assert::same('title="1"', HtmlHelpers::formatCommonAttribute('title', 1));
31+
Assert::same('title="0"', HtmlHelpers::formatCommonAttribute('title', 0));
32+
Assert::same('title="one&amp;"', HtmlHelpers::formatCommonAttribute('title', new Latte\Runtime\Html('one&amp;<br>')));
33+
Assert::same('title="one&amp;&lt;br&gt;"', HtmlHelpers::formatCommonAttribute('title', new Str));
34+
35+
// special values
36+
Assert::same('title="1"', HtmlHelpers::formatCommonAttribute('title', true));
37+
Assert::same('title=""', HtmlHelpers::formatCommonAttribute('title', false));
38+
Assert::same('title=""', HtmlHelpers::formatCommonAttribute('title', null));
39+
40+
// invalid
41+
Assert::error(
42+
fn() => Assert::same('title="Array"', HtmlHelpers::formatCommonAttribute('title', [])),
43+
E_WARNING,
44+
);
45+
Assert::exception(
46+
fn() => HtmlHelpers::formatCommonAttribute('title', (object) []),
47+
Error::class,
48+
);
49+
50+
// invalid UTF-8
51+
Assert::same( // invalid codepoint high surrogates
52+
"a=\"foo \u{FFFD} bar\"",
53+
HtmlHelpers::formatCommonAttribute('a', "foo \u{D800} bar"),
54+
);
55+
Assert::same( // stripped UTF
56+
"a=\"foo \u{FFFD}&quot; bar\"",
57+
HtmlHelpers::formatCommonAttribute('a', "foo \xE3\x80\x22 bar"),
58+
);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Latte\Runtime\XmlHelpers;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
class Str
12+
{
13+
public function __toString()
14+
{
15+
return 'one&<br>';
16+
}
17+
}
18+
19+
20+
// text
21+
Assert::same(
22+
'title="Hello &amp; Welcome"',
23+
XmlHelpers::formatCommonAttribute('title', 'Hello & Welcome'),
24+
);
25+
Assert::same(
26+
'title="&quot;Hello&quot; &amp; &apos;Welcome&apos;"',
27+
XmlHelpers::formatCommonAttribute('title', '"Hello" & \'Welcome\''),
28+
);
29+
Assert::same('title=""', XmlHelpers::formatCommonAttribute('title', ''));
30+
Assert::same('title="1"', XmlHelpers::formatCommonAttribute('title', 1));
31+
Assert::same('title="0"', XmlHelpers::formatCommonAttribute('title', 0));
32+
Assert::same('title="one&amp;"', XmlHelpers::formatCommonAttribute('title', new Latte\Runtime\Html('one&amp;<br>')));
33+
Assert::same('title="one&amp;&lt;br&gt;"', XmlHelpers::formatCommonAttribute('title', new Str));
34+
35+
// special values
36+
Assert::same('title="1"', XmlHelpers::formatCommonAttribute('title', true));
37+
Assert::same('title=""', XmlHelpers::formatCommonAttribute('title', false));
38+
Assert::same('title=""', XmlHelpers::formatCommonAttribute('title', null));
39+
40+
// invalid
41+
Assert::error(
42+
fn() => Assert::same('title="Array"', XmlHelpers::formatCommonAttribute('title', [])),
43+
E_WARNING,
44+
);
45+
Assert::exception(
46+
fn() => XmlHelpers::formatCommonAttribute('title', (object) []),
47+
Error::class,
48+
);
49+
50+
// invalid UTF-8
51+
Assert::same( // invalid codepoint high surrogates
52+
"a=\"foo \u{FFFD} bar\"",
53+
XmlHelpers::formatCommonAttribute('a', "foo \u{D800} bar"),
54+
);
55+
Assert::same( // stripped UTF
56+
"a=\"foo \u{FFFD}&quot; bar\"",
57+
XmlHelpers::formatCommonAttribute('a', "foo \xE3\x80\x22 bar"),
58+
);

tests/tags/expected/general.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public function main(array $ʟ_args): void
4343
echo '
4444
<li id="item-';
4545
echo LR\HtmlHelpers::escapeAttr($iterator->getCounter()) /* line %d%:%d% */;
46-
echo '" class="';
47-
echo LR\HtmlHelpers::escapeAttr($iterator->isOdd() ? 'odd' : 'even') /* line %d%:%d% */;
48-
echo '">';
46+
echo '"';
47+
echo LR\HtmlHelpers::formatCommonAttribute(' class', $iterator->isOdd() ? 'odd' : 'even') /* line %d%:%d% */;
48+
echo '>';
4949
echo LR\HtmlHelpers::escapeText($person) /* line %d%:%d% */;
5050
echo '</li>
5151
';

tests/tags/expected/ifchanged.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@
126126
echo ' ';
127127
ob_start(fn() => '');
128128
try /* line 22:55 */ {
129-
echo '<span class="';
130-
echo LR\HtmlHelpers::escapeAttr($i) /* line 22:50 */;
131-
echo '"></span>';
129+
echo '<span';
130+
echo LR\HtmlHelpers::formatCommonAttribute(' class', $i) /* line 22:50 */;
131+
echo '></span>';
132132
} finally {
133133
$ʟ_tmp = ob_get_clean();
134134
}

0 commit comments

Comments
 (0)