# Thumb3x - Документация

# Thumb3x: Современная обработка изображений для MODX 3

> Этот компонент был написан, чтобы заполнить пробел в экосистеме MODX 3, где практически отсутствуют современные и надежные инструменты для работы с изображениями. Большинство существующих решений не обновлялись более 10 лет и не используют преимущества новой версии системы.

## Ключевые возможности

- **Современные форматы:** Конвертация в WebP и AVIF "на лету".
- **Продвинутый движок:** В основе лежит высокопроизводительная библиотека Glide 3.0.1.
- **Интеграция с MODX 3:** Полная поддержка "Источников файлов".
- **Гибкая обработка:** Фильтры, эффекты, водяные знаки и точное позиционирование.
- **Поддержка Fenom:** Удобный вызов сниппета с передачей параметров в виде массивов.
- **Управление кэшем:** Ведение лога сгенерированных файлов в базе данных с удобной таблицей в админке.

### Стандартный вызов MODX

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-59 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQpgE" decode-data-ved="1" id="bkmrk-html" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="code-block-decoration header-formatted gds-title-s ng-tns-c985192592-59 ng-star-inserted"><span class="ng-tns-c985192592-59">HTML</span><div _ngcontent-ng-c985192592="" class="buttons ng-tns-c985192592-59 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c985192592-59 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-59"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-59">  
</div></div></div>```
<img src="[[!Thumb3x? &input=`path/to/image.jpg` &options=`w=300&h=200`]]" alt="">

```

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-59 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQpgE" decode-data-ved="1" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-59"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-59"></div></div></div>### Вызов через Fenom

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-60 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQpwE" decode-data-ved="1" id="bkmrk-%D0%A4%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82-%D0%BA%D0%BE%D0%B4%D0%B0" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="code-block-decoration header-formatted gds-title-s ng-tns-c985192592-60 ng-star-inserted"><span class="ng-tns-c985192592-60">Фрагмент кода</span><div _ngcontent-ng-c985192592="" class="buttons ng-tns-c985192592-60 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c985192592-60 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-60"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-60">  
</div></div></div>```
{'!Thumb3x' | snippet : [
    'input' => 'path/to/image.jpg',
    'options' => [
        'w' => 300,
        'h' => 200
    ]
]}

```

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-60 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQpwE" decode-data-ved="1" id="bkmrk--4" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-60"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-60"></div></div></div>## Основные параметры сниппета

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%90%D0%BB%D1%8C%D1%82%D0%B5%D1%80%D0%BD%D0%B0%D1%82%D0%B8%D0%B2"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQqAE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Альтернатива</td><td>Описание</td><td>Пример</td></tr></thead><tbody><tr><td>`input`</td><td>`i`</td><td>**(Обязательный)** Путь к исходному изображению.</td><td>`&input=`image.jpg`</td></tr><tr><td>`sourceId`</td><td> </td><td>ID "Источника файлов" для исходного изображения. По умолчанию используется значение из системных настроек.</td><td>`&sourceId=`2`</td></tr><tr><td>`quality`</td><td>`q`</td><td>**(Переопределяется `&options`)** Качество по умолчанию.</td><td>`&quality=`75`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>> warning **Важно:** Любые параметры (`q`, `fm` и т.д.), указанные внутри строки `&options`, всегда имеют наивысший приоритет.

## Справочник по параметрам обработки (`&options`)

> **Официальная документация Glide**
> 
> Компонент Thumb3x использует библиотеку **Glide** для всех операций с изображениями. Это означает, что вы можете использовать любые параметры, которые поддерживает сама библиотека.
> 
> Самую полную и актуальную информацию по всем возможным параметрам вы всегда можете найти на официальном сайте: **[https://glide.thephpleague.com/](https://glide.thephpleague.com/)**

### Размеры и ориентация

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQqwE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Ключ</td><td>Описание</td><td>Пример</td></tr></thead><tbody><tr><td>Ширина</td><td>`w`</td><td>Ширина итогового изображения в пикселях.</td><td>`w=300`</td></tr><tr><td>Высота</td><td>`h`</td><td>Высота итогового изображения в пикселях.</td><td>`h=200`</td></tr><tr><td>Вписывание</td><td>`fit`</td><td>Как вписать изображение. Основные значения: `contain`, `max`, `stretch`, `crop`.</td><td>`fit=crop`</td></tr><tr><td>Обрезка</td><td>`crop`</td><td>Точное кадрирование: `ширина,высота,x,y`.</td><td>`crop=200,150,20,50`</td></tr><tr><td>DPR</td><td>`dpr`</td><td>Множитель для Retina-дисплеев. `dpr=2` вернет картинку вдвое большего размера.</td><td>`dpr=2`</td></tr><tr><td>Ориентация</td><td>`or`</td><td>Поворачивает изображение. Значения: `auto`, `0`, `90`, `180`, `270`.</td><td>`or=90`</td></tr><tr><td>Отражение</td><td>`flip`</td><td>Отражает изображение. Значения: `v` (вертикально), `h` (горизонтально), `both`.</td><td>`flip=h`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>### Коррекция и эффекты

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-1"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQrQE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Ключ</td><td>Описание</td><td>Пример</td></tr></thead><tbody><tr><td>Яркость</td><td>`bri`</td><td>Регулировка яркости (-100 до +100).</td><td>`bri=20`</td></tr><tr><td>Контрастность</td><td>`con`</td><td>Регулировка контрастности (-100 до +100).</td><td>`con=-30`</td></tr><tr><td>Гамма</td><td>`gam`</td><td>Гамма-коррекция (0.1 до 9.99).</td><td>`gam=2.2`</td></tr><tr><td>Резкость</td><td>`sharp`</td><td>Усиление резкости (0 до 100).</td><td>`sharp=10`</td></tr><tr><td>Размытие</td><td>`blur`</td><td>Размытие по Гауссу (0 до 100).</td><td>`blur=15`</td></tr><tr><td>Пикселизация</td><td>`pixel`</td><td>Эффект пикселизации (0 до 1000).</td><td>`pixel=10`</td></tr><tr><td>Фильтр</td><td>`filt`</td><td>Применяет фильтр: `greyscale` или `sepia`.</td><td>`filt=greyscale`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>### Фон и рамка

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-2"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQrwE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Ключ</td><td>Описание</td><td>Пример</td></tr></thead><tbody><tr><td>Фон</td><td>`bg`</td><td>Цвет фона. Формат: `RRGGBB`.</td><td>`bg=CCCCCC`</td></tr><tr><td>Рамка</td><td>`border`</td><td>Добавляет рамку. Формат: `ширина,цвет,тип`. Тип: `overlay` или `shrink`.</td><td>`border=5,000000,overlay`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>### Водяные знаки

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-3"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQsQE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Ключ</td><td>Описание</td><td>Пример</td></tr></thead><tbody><tr><td>Путь</td><td>`mark`</td><td>**(Обязательный)** Имя файла водяного знака.</td><td>`mark=logo.png`</td></tr><tr><td>Ширина</td><td>`markw`</td><td>Ширина водяного знака (в px или %).</td><td>`markw=15w`</td></tr><tr><td>Высота</td><td>`markh`</td><td>Высота водяного знака (в px или %).</td><td>`markh=50`</td></tr><tr><td>Отступ X</td><td>`markx`</td><td>Отступ по горизонтали (отрицательные значения - от правого края).</td><td>`markx=-20`</td></tr><tr><td>Отступ Y</td><td>`marky`</td><td>Отступ по вертикали (отрицательные значения - от нижнего края).</td><td>`marky=-20`</td></tr><tr><td>Отступы</td><td>`markpad`</td><td>Отступы со всех сторон.</td><td>`markpad=10`</td></tr><tr><td>Позиция</td><td>`markpos`</td><td>Позиция: `top-left`, `center`, `bottom-right` и т.д.</td><td>`markpos=top-left`</td></tr><tr><td>Прозрачность</td><td>`markalpha`</td><td>Прозрачность водяного знака (0-100).</td><td>`markalpha=50`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>### Выходной формат

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-4"><div class="table-block-component"><div _ngcontent-ng-c3731732941="" class="table-block has-export-button"><div _ngcontent-ng-c3731732941="" class="table-content not-end-of-paragraph" data-hveid="0" data-ved="0CAAQ3ecQahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQswE" decode-data-ved="1" jslog="275421;track:impression,attention" not-end-of-paragraph=""><table><thead><tr><td>Параметр</td><td>Ключ</td><td>Описание</td><td>Значения</td><td>Пример</td></tr></thead><tbody><tr><td>Формат</td><td>`fm`</td><td>Формат итогового изображения.</td><td>`jpg`, `png`, `gif`, `webp`, `avif`</td><td>`fm=webp`</td></tr><tr><td>Качество</td><td>`q`</td><td>Качество для `jpg`, `webp`, `avif`.</td><td>`0` до `100`</td><td>`q=80`</td></tr></tbody></table>

</div><div _ngcontent-ng-c3731732941="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions=""><button class="mdc-button mat-mdc-button-base export-sheets-button-container mat-mdc-button mat-unthemed _mat-animation-noopable ng-star-inserted"><span class="mdc-button__label"><span class="export-sheets-button">Экспортировать в Таблицы</span></span></button></div></div></div></div>## Развернутые примеры вызова

### Пример 1: Наложение водяного знака (стандартный вызов MODX)

**Задача:** Наложить `logo.png` в правый нижний угол с отступом и полупрозрачностью.

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-61 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQtQE" decode-data-ved="1" id="bkmrk-html-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="code-block-decoration header-formatted gds-title-s ng-tns-c985192592-61 ng-star-inserted"><span class="ng-tns-c985192592-61">HTML</span><div _ngcontent-ng-c985192592="" class="buttons ng-tns-c985192592-61 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c985192592-61 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-61"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-61">  
</div></div></div>```
<img src="[[!Thumb3x?
    &input=`portfolio/image-01.jpg`
    &watermark=`assets/watermark/logo.png`
    &options=`w=1200&mark=logo.png&markpos=bottom-right&markpad=30&markalpha=50`
]]" alt="Портфолио с водяным знаком">

```

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-61 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQtQE" decode-data-ved="1" id="bkmrk--7" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-61"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-61"></div></div></div>### Пример 2: Вызов через Fenom

**Задача:** Сделать то же самое, используя более читаемый синтаксис Fenom с передачей параметров в виде массива.

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-62 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQtgE" decode-data-ved="1" id="bkmrk-%D0%A4%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82-%D0%BA%D0%BE%D0%B4%D0%B0-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="code-block-decoration header-formatted gds-title-s ng-tns-c985192592-62 ng-star-inserted"><span class="ng-tns-c985192592-62">Фрагмент кода</span><div _ngcontent-ng-c985192592="" class="buttons ng-tns-c985192592-62 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c985192592-62 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-62"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-62">  
</div></div></div>```
{* Определяем параметры для Glide в виде массива *}
{var $params = [
    'w' => 1200,
    'h' => 800,
    'mark' => 'logo.png',
    'markpos' => 'bottom-right',
    'markpad' => 20,
    'markalpha' => 60
]}

{* Вызываем сниппет *}
<img src="{'!Thumb3x' | snippet : [
    'input' => 'portfolio/image-01.jpg',
    'watermark' => 'assets/images/logo.png',
    'options' => $params
]}" alt="Изображение с водяным знаком">

```

<div _ngcontent-ng-c985192592="" class="code-block ng-tns-c985192592-62 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiI-6CPqIOQAxUAAAAAHQAAAAAQtgE" decode-data-ved="1" id="bkmrk--10" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_22df14b5d39da696","c_25e9c3d526b5ad44",null,"rc_6e5f90e1aef31877",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c985192592="" class="formatted-code-block-internal-container ng-tns-c985192592-62"><div _ngcontent-ng-c985192592="" class="animated-opacity ng-tns-c985192592-62"></div></div></div>**Пояснение:** Главное преимущество Fenom здесь — возможность собрать все параметры обработки в аккуратный массив `$params`, что делает код шаблона намного чище и удобнее для чтения и редактирования.