Files
Twig/extra/html-extra/HtmlExtension.php
T
Fabien Potencier ef7ade8ee3 Merge branch '3.x' into 4.x
* 3.x: (30 commits)
  Make {} optional for the types tag
  Remove the note about types mapping argument
  Add a note on the types locality
  Fix CS
  Fix typos in the docs
  Use spl_object_id() instead of spl_object_hash()
  Add `LastModifiedExtensionInterface` and implementation in `AbstractExtension` to track modification of runtime classes
  Bump version
  Optimize NameExpression compilation
  Fix typo in enum twig doc functions
  Remove dead method in ModuleNode
  Bump version
  Prepare the 3.18.0 release
  Add support for `Twig\Markup`
  Fix unary operator precedence change
  Replace Twigfiddle by the new Twig playground
  Fix MacroNode $name argument can be overridden
  Ignore exceptions from undefined handlers when using the guard tag
  [Doc] Update the docs about attribute() function
  Fix doc
  ...
2025-01-10 08:41:31 +01:00

129 lines
3.7 KiB
PHP

<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extra\Html;
use Symfony\Component\Mime\MimeTypes;
use Twig\Error\RuntimeError;
use Twig\Extension\AbstractExtension;
use Twig\Markup;
use Twig\TwigFilter;
use Twig\TwigFunction;
final class HtmlExtension extends AbstractExtension
{
private $mimeTypes;
public function __construct(?MimeTypes $mimeTypes = null)
{
$this->mimeTypes = $mimeTypes;
}
public function getFilters(): array
{
return [
new TwigFilter('data_uri', [$this, 'dataUri']),
];
}
public function getFunctions(): array
{
return [
new TwigFunction('html_classes', self::htmlClasses(...)),
new TwigFunction('html_cva', self::htmlCva(...)),
];
}
/**
* Creates a data URI (RFC 2397).
*
* Length validation is not performed on purpose, validation should
* be done before calling this filter.
*
* @return string The generated data URI
*
* @internal
*/
public function dataUri(string $data, ?string $mime = null, array $parameters = []): string
{
$repr = 'data:';
if (null === $mime) {
if (null === $this->mimeTypes) {
$this->mimeTypes = new MimeTypes();
}
$tmp = tempnam(sys_get_temp_dir(), 'mime');
file_put_contents($tmp, $data);
try {
if (null === $mime = $this->mimeTypes->guessMimeType($tmp)) {
$mime = 'text/plain';
}
} finally {
@unlink($tmp);
}
}
$repr .= $mime;
foreach ($parameters as $key => $value) {
$repr .= ';'.$key.'='.rawurlencode($value);
}
if (str_starts_with($mime, 'text/')) {
$repr .= ','.rawurlencode($data);
} else {
$repr .= ';base64,'.base64_encode($data);
}
return $repr;
}
/**
* @internal
*/
public static function htmlClasses(...$args): string
{
$classes = [];
foreach ($args as $i => $arg) {
if (\is_string($arg) || $arg instanceof Markup) {
$classes[] = (string) $arg;
} elseif (\is_array($arg)) {
foreach ($arg as $class => $condition) {
if (!\is_string($class)) {
throw new RuntimeError(\sprintf('The "html_classes" function argument %d (key %d) should be a string, got "%s".', $i, $class, get_debug_type($class)));
}
if (!$condition) {
continue;
}
$classes[] = $class;
}
} else {
throw new RuntimeError(\sprintf('The "html_classes" function argument %d should be either a string or an array, got "%s".', $i, get_debug_type($arg)));
}
}
return implode(' ', array_unique(array_filter($classes, static function ($v) { return '' !== $v; })));
}
/**
* @param string|list<string|null> $base
* @param array<string, array<string, string|array<string>> $variants
* @param array<array<string, string|array<string>>> $compoundVariants
* @param array<string, string> $defaultVariant
*
* @internal
*/
public static function htmlCva(array|string $base = [], array $variants = [], array $compoundVariants = [], array $defaultVariant = []): Cva
{
return new Cva($base, $variants, $compoundVariants, $defaultVariant);
}
}