diff --git a/extra/html-extra/HtmlExtension.php b/extra/html-extra/HtmlExtension.php index ed740b47187..e0cf3342425 100644 --- a/extra/html-extra/HtmlExtension.php +++ b/extra/html-extra/HtmlExtension.php @@ -28,6 +28,14 @@ public function getFilters(): array { return [ new TwigFilter('data_uri', [$this, 'dataUri']), + new TwigFilter( + 'html_attributes', + [$this, 'htmlAttributes'], + [ + 'is_safe' => ['html'], + 'needs_environment' => true, + ] + ), ]; } @@ -79,6 +87,35 @@ public function dataUri(string $data, string $mime = null, array $parameters = [ return $repr; } + + /** + * @param array{string, string|bool|int|float|null} $attributes + */ + public function htmlAttributes(Environment $environment, array $attributes): string + { + /** @var string[] $htmlAttributes */ + $htmlAttributes = []; + foreach ($attributes as $key => $value) { + if (\is_bool($value)) { + // false should never be outputted e.g. disabled, readonly + // this matches also the behaviour here: https://github.com/symfony/symfony/blob/v5.4.14/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig#L465-L476 + if ($value) { + $htmlAttributes[] = $key; + } + + continue; + } + + // null represent no value and should not be outputted for a better DX + if (null === $value) { + continue; + } + + $htmlAttributes[] = $key . '="' . twig_escape_filter($environment, $value) . '"'; + } + + return implode(' ', $htmlAttributes); + } } }