bin/console make:twig-extension - создаст файл, в котором по умолчанию будет 3 метода getFilters(), getFunctions() и doSomething($value), которые служат для создания кастомных фильтров, кастомных функций и соответственно логики описывающих их. Так же этот файл наследуется от AbstractExtension
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class AppExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('filter_name', [$this, 'doSomething'], ['is_safe' => ['html']]),
];
}
public function getFunctions(): array
{
return [
new TwigFunction('function_name', [$this, 'doSomething']),
];
}
public function doSomething($value)
{
// ...
}
}
При использовании конфигурации service.yaml по умолчанию, Symfony автоматически узнает о новом функционале.
Например, мы хотим добавить extention который будет переводить весь текст в верхний регистр и у нас есть сервис позволяюший это сделать. Логика:
- Через
getFilters()описывает как будет называться новый фильтр и в какой функции(processUpper) будет описана локика его работы - В конструкторе получаем нужный сервис(
StrHelper) черезDI
// src/Service/StrHelper.php
namespace App\Service;
class StrHelper
{
public function toUpper(string $source): string
{
return strtoupper($source);
}
}
// src/Twig/AppExtension.php
namespace App\Twig;
use App\Service\StrHelper;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class AppExtension extends AbstractExtension
{
private $strHelper;
public function __construct(StrHelper $strHelper)
{
$this->strHelper = $strHelper;
}
public function getFilters(): array
{
return [
new TwigFilter('str_upper', [$this, 'processUpper'], ['is_safe' => ['html']]),
];
}
public function processUpper($value)
{
return $this->strHelper->toUpper($value);
}
}
Использование в Twig - {{ content|str_upper }}
В обычной реализации кастомный twig-extention будет загружен всегда и это будет влиять на производительность системы. Однако есть возможность для ленивой(отложенной) загрузки.
Заставим класс AppExtension реализовать интерфейс ServiceSubscriberInterface. Теперь нам необходимо реализовать новый метод - getSubscribedServices. Так же добавим конструктор в который передадим контейнер - это ContainerInterface из PSR.
Таким образом Symfony попытается передам к нам в файл service-container, однако это будет контейнер не со всеми службами(где могут быть сотни сервисов), а мини-контейнер. Что бы сообщить Symfony какие услуги необходимо использовать в своём мини-контейнере мы и воспользуемся методом getSubscribedServices(), в котором будем возвращать необходимый сервис(необходимый сервис - это наш функционал(логика) который хотим использовать как twig-extention - например, мы пишем фильтр который будет переводить текст в верхний регистр см. описание выше).
В итоге, если на странице не используется наш кастомный фильтр, то и загрузка сервиса выполняться не будет.
namespace App\Twig;
use App\Service\StrHelper;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class AppExtension extends AbstractExtension implements ServiceSubscriberInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getFilters(): array
{
return [
new TwigFilter('str_upper', [$this, 'processUpper'], ['is_safe' => ['html']]),
];
}
public function processUpper($value)
{
return $this->container
->get(StrHelper::class)
->toUpper($value);
}
public static function getSubscribedServices()
{
return [
StrHelper::class,
];
}
}
Необходимо содать отдельный класс(напрю AppRuntime), который реализует RuntimeExtensionInterface и внедряет наш кастомынй StrHelper. Так же сюда переедет логика работы(метод processUpper()).
namespace App\Twig;
use App\Service\StrHelper;
use Twig\Extension\RuntimeExtensionInterface;
class AppRuntime implements RuntimeExtensionInterface
{
private $strHelper;
public function __construct(StrHelper $strHelper)
{
$this->strHelper = $strHelper;
}
public function processUpper($value)
{
return $this->strHelper->toUpper($value);
}
}
Т.е. из файла src/Twig/AppExtension.php убирается конструктор и processUpper(). И изменяется вызов в фильтре:
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class AppExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('str_upper', [AppRuntime::class, 'processUpper'], ['is_safe' => ['html']]),
];
}
}