fix of setEscaper move in Twig 3.9+

Signed-off-by: Andy Miller <rhuk@mac.com>
This commit is contained in:
Andy Miller
2025-12-22 21:43:10 -07:00
parent 6b54b32140
commit 0e4f37eca7
2 changed files with 58 additions and 17 deletions

View File

@@ -33,12 +33,14 @@ use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\CoreExtension;
use Twig\Extension\DebugExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\StringLoaderExtension;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\ExistsLoaderInterface;
use Twig\Loader\FilesystemLoader;
use Twig\Profiler\Profile;
use Twig\Runtime\EscaperRuntime;
use Twig\TwigFilter;
use Twig\TwigFunction;
use function function_exists;
@@ -594,4 +596,34 @@ class Twig
$this->autoescape = (bool) $state;
}
/**
* Register a custom escaper strategy.
*
* This method handles the differences between Twig versions:
* - Twig 1.x: Uses CoreExtension::setEscaper()
* - Twig 2.x/3.x (< 3.9): Uses EscaperExtension::setEscaper()
* - Twig 3.9+: Uses EscaperRuntime::setEscaper()
*
* @param string $strategy The escaper strategy name (e.g., 'yaml', 'json')
* @param callable $callable The escaper callable: function($twig, $string, $charset)
* @return void
*/
public function setEscaper(string $strategy, callable $callable): void
{
// Twig 3.9+ moved setEscaper to EscaperRuntime
if (class_exists(EscaperRuntime::class)) {
$this->twig->getRuntime(EscaperRuntime::class)->setEscaper($strategy, $callable);
return;
}
// Twig 2.x/3.x (before 3.9) uses EscaperExtension
if (class_exists(EscaperExtension::class)) {
$this->twig->getExtension(EscaperExtension::class)->setEscaper($strategy, $callable);
return;
}
// Twig 1.x fallback (uses CoreExtension)
$this->twig->getExtension(CoreExtension::class)->setEscaper($strategy, $callable);
}
}

View File

@@ -9,6 +9,7 @@
namespace Grav\Common\Twig;
use ReflectionClass;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Extension\EscaperExtension;
@@ -32,27 +33,35 @@ class TwigEnvironment extends Environment
{
$extension = parent::getExtension($name);
// Provide setEscaper() compatibility shim for older code calling it on the extension.
// In Twig 3.9+, setEscaper() moved to EscaperRuntime.
// In Twig 3.10+, EscaperExtension is final and cannot be extended.
if ($name === EscaperExtension::class && class_exists(EscaperRuntime::class)) {
return new class($extension, $this) extends EscaperExtension {
private $original;
private $env;
$reflection = new ReflectionClass(EscaperExtension::class);
if (!$reflection->isFinal()) {
return new class($extension, $this) extends EscaperExtension {
private $original;
private $env;
public function __construct($original, $env)
{
$this->original = $original;
$this->env = $env;
}
public function __construct($original, $env)
{
$this->original = $original;
$this->env = $env;
}
public function setEscaper($strategy, $callable)
{
$this->env->getRuntime(EscaperRuntime::class)->setEscaper($strategy, $callable);
}
public function setEscaper($strategy, $callable)
{
$this->env->getRuntime(EscaperRuntime::class)->setEscaper($strategy, $callable);
}
public function getDefaultStrategy($filename)
{
return $this->original->getDefaultStrategy($filename);
}
};
public function getDefaultStrategy($filename)
{
return $this->original->getDefaultStrategy($filename);
}
};
}
// When EscaperExtension is final (Twig 3.10+), setEscaper() must be called
// directly on the runtime: $twig->getRuntime(EscaperRuntime::class)->setEscaper(...)
}
return $extension;