Як написати користувацьке розширення Twig

Дата оновлення перекладу 2022-11-24

Як написати користувацьке розширення Twig

Розширення Twig дозволяють створювати користувацькі функції, фільтри та інше для використання у ваших шаблонах Twig. Перед написанням власного розширення Twig, перевірте, чи не реалізовано вже необхідний вам фільтр/функцію у:

Створіть клас розширення

Уявіть, що ви хочете створити новий фільтр під назвою price, який форматує число у грошове значення:

1
2
3
4
{{ product.price|price }}

{# передайте в 3 необовʼязкових аргументах #}
{{ product.price|price(2, ',', '.') }}

Створіть клас, що розширює AbstractExtension, і заповніть лоігку:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Twig/AppExtension.php
namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('price', [$this, 'formatPrice']),
        ];
    }

    public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string
    {
        $price = number_format($number, $decimals, $decPoint, $thousandsSep);
        $price = '$'.$price;

        return $price;
    }
}

Якщо ви хочете створити функцію, а не фільтр, визначіть метод getFunctions():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Twig/AppExtension.php
namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class AppExtension extends AbstractExtension
{
    public function getFunctions()
    {
        return [
            new TwigFunction('area', [$this, 'calculateArea']),
        ];
    }

    public function calculateArea(int $width, int $length): int
    {
        return $width * $length;
    }
}

Tip

Окрім користувацьких фільтрів та функцій, ви також можете реєструвати глобальні змінні.

Реєстрація розширення в якості сервісу

Далі, зареєструйте ваш клас в якості сервісу та тегуйте його twig.extension. Якщо ви використовуєте конфігурацію services.yml за замовчуванням , то ви закінчили! Symfony автоматично дізнається про ваш новий сервіс та додасть тег.

Тепер ви можете почати використовувати ваш фільтр у будь-якому шаблоні Twig. Опціонально, виконайте цю команду, щоб підтвердити, що ваш новий фільтр було успішно зареєстровано:

1
2
3
4
5
# відобразити всю інформацію про Twig
$ php bin/console debug:twig

# відобразити лише інформацію про конкретний фільтр
$ php bin/console debug:twig --filter=price

Створення лінивозавантажуваних розширень Twig

1.35

Підтримка лінивозавантажуваних розширень була представлена в Twig 1.35.0 та 2.4.4.

Включення коду користувацьких фільтрів/функцій у клас розширення Twig - це найпроостіший спосіб створення розширень. Однак, Twig повинен ініціювати всі розширення перед відображенням будь-якого шаблону, навіть якщо шаблон не використовує розширення.

Якщо розширення не визначають залежностей (тобто, якщо ви не впроваджуєте сервіси у них), продуктивність не стаждає. Однак, якщо розширення визначають багато складних залежностей (наприклад, таких, які роблять зʼєднання бази даних), втрата продуктивності може бути суттєвою.

Тому Twig дозволяє розʼєднання визначення розширення та його реалізації. Дотримуючись того ж прикладу, що і раніше, першою зміною буде видалення методу formatPrice() з розширення та оновлення викличного PHP, визначеного у getFilters():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/Twig/AppExtension.php
namespace App\Twig;

use App\Twig\AppRuntime;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            // логіка цього фільтру тепер реалізується в іншому класі
            new TwigFilter('price', [AppRuntime::class, 'formatPrice']),
        ];
    }
}

Потім створіть новий клас AppRuntime (це не обовʼязково, але ці класи мають суфікс Runtime за угодою) так включіть логіку попередього методу formatPrice():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Twig/AppRuntime.php
namespace App\Twig;

use Twig\Extension\RuntimeExtensionInterface;

class AppRuntime implements RuntimeExtensionInterface
{
    public function __construct()
    {
        // цей простий приклад не визначає жодної залежності, але у ваших власних
        // розширеннях, вам знадобиться впровадити сервіси, використовуючи цей конструкто
    }

    public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string
    {
        $price = number_format($number, $decimals, $decPoint, $thousandsSep);
        $price = '$'.$price;

        return $price;
    }
}

Якщо ви використовуєте конфігурацію services.yaml за замовчуванням, це вже працюватиме! В інших випадках, створіть срвіс для цього класу і тегуйте ваш сервіс за допомогою twig.runtime.