Фильтры (Pipes)
Полное руководство по фильтрам для обработки и форматирования данных
Основы фильтров
Фильтры позволяют трансформировать данные перед выводом. Они применяются с помощью символа | (pipe):
<!-- Базовый синтаксис -->
{{ variable | filter }}
<!-- Фильтр с параметрами -->
{{ variable | filter(param1, param2) }}
<!-- Цепочка фильтров -->
{{ variable | filter1 | filter2 | filter3 }}
Текстовые фильтры
Изменение регистра
<!-- Данные для примеров -->
{% set greeting = "привет мир" %}
{% set shout = "ПРИВЕТ МИР" %}
{% set sentence = "привет. как дела?" %}
<!-- Верхний регистр -->
{{ greeting | upper }} <!-- Результат: ПРИВЕТ МИР -->
{{ "привет мир" | upper }} <!-- Альтернативный способ -->
<!-- Нижний регистр -->
{{ shout | lower }} <!-- Результат: привет мир -->
<!-- Первая буква каждого слова заглавная -->
{{ greeting | title }} <!-- Результат: Привет Мир -->
<!-- Первая буква предложения заглавная -->
{{ sentence | capitalize }} <!-- Результат: Привет. как дела? -->
Обрезка и очистка
<!-- Данные для примеров -->
{% set messy_text = " текст с пробелами " %}
{% set user = {
'bio': 'Я занимаюсь веб-разработкой уже более 10 лет. Специализируюсь на PHP, JavaScript и современных фреймворках. В свободное время изучаю новые технологии.'
} %}
{% set article = {
'text': 'Веб-разработка сегодня требует знания множества технологий и инструментов. От базового HTML и CSS до сложных фреймворков и систем управления состоянием.'
} %}
<!-- Удаление пробелов -->
{{ messy_text | trim }} <!-- Результат: "текст с пробелами" -->
<!-- Обрезка по длине символов -->
{{ user.bio | truncate(50) }} <!-- Первые 50 символов + "..." -->
{{ user.bio | truncate(100, '…') }} <!-- Первые 100 символов + "…" -->
{{ user.bio | truncate(80, ' →') }} <!-- Первые 80 символов + " →" -->
<!-- Обрезка по количеству слов -->
{{ article.text | truncate_words(10) }} <!-- Первые 10 слов + "..." -->
{{ article.text | truncate_words(15, '…') }} <!-- Первые 15 слов + "…" -->
HTML и экранирование
<!-- Данные для примеров -->
{% set user = {
'description': "Первая строка\nВторая строка\nТретья строка",
'input': '<script>alert("XSS");</script>Безопасный текст'
} %}
{% set article = {
'content': '<p>Статья с <strong>форматированием</strong></p><script>alert("bad");</script>'
} %}
{% set search_query = "поиск с пробелами & символами" %}
<!-- Преобразование переносов строк в <br> -->
{{ user.description | nl2br }}
<!-- Результат: Первая строка<br>Вторая строка<br>Третья строка -->
<!-- HTML экранирование (защита от XSS) -->
{{ user.input | escape }}
<!-- Результат: <script>alert("XSS");</script>Безопасный текст -->
<!-- Удаление HTML тегов -->
{{ article.content | strip_tags }}
<!-- Результат: Статья с форматированиемalert("bad"); -->
<!-- URL кодирование для использования в ссылках -->
{{ search_query | urlencode }}
<!-- Результат: поиск+с+пробелами+%26+символами -->
<!-- URL декодирование -->
{{ "поиск+с+пробелами" | urldecode }}
<!-- Результат: поиск с пробелами -->
Работа с текстом
<!-- Данные для примеров -->
{% set user = { 'name': 'Иван Петров' } %}
{% set test_string = "Тестовая строка" %}
{% set tags = ['php', 'javascript', 'html', 'css'] %}
{% set csv_string = "яблоко,банан,апельсин,груша" %}
<!-- Длина строки -->
{{ user.name | length }} <!-- Результат: 11 символов -->
{{ test_string | length }} <!-- Результат: 14 символов -->
<!-- Замена текста -->
{{ "Hello World" | replace("World", "Universe") }}
<!-- Результат: Hello Universe -->
{{ user.name | replace("Иван", "Александр") }}
<!-- Результат: Александр Петров -->
<!-- Объединение массива в строку -->
{{ tags | join(', ') }} <!-- Результат: php, javascript, html, css -->
{{ tags | join(' | ') }} <!-- Результат: php | javascript | html | css -->
<!-- Разделение строки на массив -->
{{ csv_string | split(',') }} <!-- Результат: ['яблоко', 'банан', 'апельсин', 'груша'] -->
<!-- Использование split с foreach -->
{% foreach csv_string | split(',') as fruit %}
<li>{{ fruit | trim }}</li> <!-- Убираем лишние пробелы -->
{% endforeach %}
Числовые фильтры
Форматирование чисел
<!-- Данные для примеров -->
{% set price = 1234.567 %}
{% set big_number = 1234567.89 %}
{% set money_amount = 1234.50 %}
<!-- Базовое форматирование чисел -->
{{ price | number }} <!-- Результат: 1,235 (округление до целого) -->
{{ price | number(2) }} <!-- Результат: 1,234.57 (2 знака после запятой) -->
{{ price | number(0) }} <!-- Результат: 1,235 (без дробной части) -->
{{ price | number(3) }} <!-- Результат: 1,234.567 (3 знака) -->
<!-- Кастомные разделители: number(знаки_после_запятой, десятичный_разделитель, разделитель_тысяч) -->
{{ big_number | number(2, ',', ' ') }} <!-- Результат: 1 234 567,89 (европейский формат) -->
{{ big_number | number(2, '.', "'") }} <!-- Результат: 1'234'567.89 (швейцарский формат) -->
<!-- Форматирование валюты -->
{{ money_amount | money }} <!-- Результат: $1,234.50 (доллары по умолчанию) -->
{{ money_amount | money('₽') }} <!-- Результат: ₽1,234.50 (рубли) -->
{{ money_amount | money('€') }} <!-- Результат: €1,234.50 (евро) -->
<!-- Кастомное форматирование валюты: money(символ, знаки, десятичный_разделитель, разделитель_тысяч) -->
{{ money_amount | money('€', 2, ',', '.') }} <!-- Результат: €1.234,50 (немецкий формат) -->
Математические операции
<!-- Данные для примеров -->
{% set pi = 3.14159 %}
{% set positive = 3.8 %}
{% set negative = -42 %}
{% set exact = 3.2 %}
<!-- Округление -->
{{ pi | round }} <!-- Результат: 3 (до ближайшего целого) -->
{{ pi | round(2) }} <!-- Результат: 3.14 (2 знака после запятой) -->
{{ pi | round(4) }} <!-- Результат: 3.1416 (4 знака) -->
<!-- Округление вниз (к меньшему целому) -->
{{ positive | floor }} <!-- Результат: 3 -->
{{ pi | floor }} <!-- Результат: 3 -->
<!-- Округление вверх (к большему целому) -->
{{ exact | ceil }} <!-- Результат: 4 -->
{{ pi | ceil }} <!-- Результат: 4 -->
<!-- Абсолютное значение (модуль числа) -->
{{ negative | abs }} <!-- Результат: 42 -->
{{ positive | abs }} <!-- Результат: 3.8 (число уже положительное) -->
Проценты
<!-- Данные для примеров -->
{% set discount_rate = 0.15 %}
{% set precise_rate = 0.1567 %}
{% set total_amount = 1000 %}
{% set discount_amount = 150 %}
<!-- Форматирование процентов (из десятичной дроби) -->
{{ discount_rate | percent }} <!-- Результат: 15% -->
{{ precise_rate | percent(2) }} <!-- Результат: 15.67% (2 знака после запятой) -->
<!-- Расчет процентов из данных -->
{{ (discount_amount / total_amount) | percent }}
<!-- Результат: 15% (150/1000 = 0.15 = 15%) -->
<!-- Практический пример: скидка на товар -->
{% set product = {
'price': 2000,
'sale_price': 1600
} %}
{% set discount_percent = ((product.price - product.sale_price) / product.price) | percent %}
<p>Скидка: {{ discount_percent }}</p> <!-- Результат: Скидка: 20% -->
Фильтры дат
Базовое форматирование
<!-- Данные для примеров -->
{% set user = {
'created_at': '2024-01-15 14:30:45',
'birth_date': '1990-05-20'
} %}
{% set event = {
'start_time': '2024-02-01 14:30:00',
'end_time': '2024-02-01 18:45:00'
} %}
{% set order = {
'created_at': '2024-01-15 14:30:45'
} %}
<!-- Стандартные форматы дат -->
{{ user.created_at | date('Y-m-d') }} <!-- Результат: 2024-01-15 -->
{{ user.created_at | date('d.m.Y') }} <!-- Результат: 15.01.2024 -->
{{ user.created_at | date('d.m.Y H:i') }} <!-- Результат: 15.01.2024 14:30 -->
{{ user.birth_date | date('F j, Y') }} <!-- Результат: May 20, 1990 -->
<!-- Форматирование времени -->
{{ event.start_time | date('H:i') }} <!-- Результат: 14:30 (24-часовой формат) -->
{{ event.start_time | date('g:i A') }} <!-- Результат: 2:30 PM (12-часовой формат) -->
<!-- Полная дата и время с текстом -->
{{ order.created_at | date('d.m.Y в H:i:s') }} <!-- Результат: 15.01.2024 в 14:30:45 -->
<!-- Русские названия месяцев (если поддерживается локализацией) -->
{{ user.created_at | date('j F Y г.') }} <!-- Результат: 15 January 2024 г. -->
Работа с текущим временем
<!-- Данные для примеров -->
{% set user = {
'last_login': 1705332000
} %}
<!-- Текущее время -->
{{ 'now' | date('Y-m-d H:i:s') }} <!-- Результат: 2024-01-15 14:30:45 -->
{{ 'now' | date('d.m.Y') }} <!-- Результат: 15.01.2024 -->
<!-- Время для разных задач -->
<p>Сегодня: {{ 'now' | date('d.m.Y') }}</p>
<p>Сейчас: {{ 'now' | date('H:i') }}</p>
<!-- Работа с временными интервалами -->
{% set time_diff = time() - user.last_login %}
<p>Не был в сети: {{ time_diff }} секунд</p>
<!-- Форматирование интервала времени как время -->
{% if time_diff < 86400 %} <!-- если меньше суток -->
<p>Прошло времени: {{ time_diff | date('H:i:s', true) }}</p>
{% endif %}
Фильтры массивов
Основные операции
<!-- Данные для примеров -->
{% set users = [
{'name': 'Иван', 'age': 25},
{'name': 'Мария', 'age': 30},
{'name': 'Петр', 'age': 22}
] %}
{% set numbers = [3, 1, 4, 1, 5, 9, 2, 6] %}
{% set fruits = ['яблоко', 'банан', 'яблоко', 'апельсин', 'банан'] %}
<!-- Длина массива (количество элементов) -->
{{ users | length }} <!-- Результат: 3 -->
{{ numbers | length }} <!-- Результат: 8 -->
<!-- Первый и последний элементы -->
{{ users | first }} <!-- Результат: {'name': 'Иван', 'age': 25} -->
{{ users | last }} <!-- Результат: {'name': 'Петр', 'age': 22} -->
<!-- Срез массива: slice(начало, количество) -->
{{ numbers | slice(0, 3) }} <!-- Результат: [3, 1, 4] (первые 3 элемента) -->
{{ numbers | slice(2, 4) }} <!-- Результат: [4, 1, 5, 9] (с 3-го элемента, 4 штуки) -->
{{ users | slice(1, 2) }} <!-- Результат: [{'name': 'Мария', 'age': 30}, {'name': 'Петр', 'age': 22}] -->
Сортировка и фильтрация
<!-- Данные для примеров -->
{% set users = [
{'name': 'Петр', 'age': 22, 'salary': 50000},
{'name': 'Иван', 'age': 25, 'salary': 60000},
{'name': 'Мария', 'age': 30, 'salary': 75000}
] %}
{% set products = [
{'name': 'Ноутбук', 'price': 80000, 'category': 'electronics'},
{'name': 'Мышь', 'price': 1500, 'category': 'electronics'},
{'name': 'Книга', 'price': 500, 'category': 'books'}
] %}
{% set numbers = [3, 1, 4, 1, 5, 9, 2, 6] %}
{% set tags = ['php', 'javascript', 'php', 'html', 'css', 'javascript'] %}
<!-- Простая сортировка массива -->
{{ numbers | sort }} <!-- Результат: [1, 1, 2, 3, 4, 5, 6, 9] (по возрастанию) -->
{{ numbers | sort('asc') }} <!-- Результат: [1, 1, 2, 3, 4, 5, 6, 9] -->
{{ numbers | sort('desc') }} <!-- Результат: [9, 6, 5, 4, 3, 2, 1, 1] (по убыванию) -->
<!-- Сортировка объектов по полю -->
{{ users | sort_by('name') }} <!-- Сортировка по имени (А-Я) -->
{{ users | sort_by('age', 'asc') }} <!-- Сортировка по возрасту (младше → старше) -->
{{ products | sort_by('price', 'desc') }} <!-- Сортировка по цене (дороже → дешевле) -->
<!-- Обратный порядок -->
{{ users | reverse }} <!-- Меняет порядок элементов на противоположный -->
<!-- Уникальные значения (удаление дубликатов) -->
{{ tags | unique }} <!-- Результат: ['php', 'javascript', 'html', 'css'] -->
<!-- Пример: отсортированные уникальные теги -->
{{ tags | unique | sort }} <!-- Результат: ['css', 'html', 'javascript', 'php'] -->
Ключи и значения
<!-- Данные для примеров -->
{% set config = {
'app_name': 'Мое приложение',
'debug': true,
'database': {
'host': 'localhost',
'port': 3306
},
'cache_enabled': false
} %}
{% set user = {
'name': 'Иван Петров',
'email': 'ivan@example.com',
'password': 'secret123',
'role': 'admin'
} %}
{% set orders = [
{'id': 1, 'status': 'completed', 'user_id': 10},
{'id': 2, 'status': 'pending', 'user_id': 15},
{'id': 3, 'status': 'completed', 'user_id': 10},
{'id': 4, 'status': 'cancelled', 'user_id': 20}
] %}
<!-- Извлечение ключей и значений -->
{{ config | keys }} <!-- Результат: ['app_name', 'debug', 'database', 'cache_enabled'] -->
{{ config | values }} <!-- Результат: ['Мое приложение', true, {...}, false] -->
<!-- Дополнительные операции с ключами -->
{{ config | has_key('database') }} <!-- Результат: true (проверить наличие ключа) -->
{{ config | get('app_name', 'Default App') }} <!-- Результат: 'Мое приложение' (получить с дефолтом) -->
{{ config | get('missing_key', 'Дефолт') }} <!-- Результат: 'Дефолт' -->
<!-- Выбор/исключение полей -->
{{ user | pick('name', 'email') }} <!-- Результат: {'name': 'Иван Петров', 'email': 'ivan@example.com'} -->
{{ user | omit('password', 'secret') }} <!-- Исключить поля password и secret -->
<!-- Преобразование в массив -->
{{ config | to_array | keys }} <!-- Преобразовать объект в массив и получить ключи -->
<!-- Рекурсивное получение всех ключей (включая вложенные) -->
{{ config | keys_recursive }} <!-- Результат: ['app_name', 'debug', 'database', 'database.host', 'database.port', 'cache_enabled'] -->
<!-- Группировка элементов по полю -->
{{ orders | group_by('status') }} <!-- Группировка заказов по статусу -->
<!-- Результат: {
'completed': [{'id': 1, ...}, {'id': 3, ...}],
'pending': [{'id': 2, ...}],
'cancelled': [{'id': 4, ...}]
} -->
<!-- Практические примеры использования -->
<!-- Перебор ключей конфигурации -->
<ul>
{% foreach config | keys as key %}
<li>{{ key }}: {{ config | get(key) }}</li>
{% endforeach %}
</ul>
<!-- Проверка наличия ключа -->
{% if config | has_key('debug') %}
<p>Режим отладки: {{ config.debug ? 'включен' : 'выключен' }}</p>
{% endif %}
<!-- Создание отсортированного списка настроек -->
<ul>
{% foreach config | keys | sort as key %}
<li><strong>{{ key }}:</strong> {{ config | get(key) }}</li>
{% endforeach %}
</ul>
Условные фильтры
Значения по умолчанию
<!-- Данные для примеров -->
{% set user = {
'name': 'Иван',
'nickname': null,
'bio': '',
'avatar': '/path/image.jpg',
'tags': []
} %}
{% set product = {
'name': 'Товар',
'image': null,
'price': 0,
'description': false
} %}
<!-- БАЗОВЫЙ default - для всех "пустых" значений (null, '', [], false, 0) -->
{{ user.nickname | default('Аноним') }} <!-- null → 'Аноним' -->
{{ user.bio | default('Нет описания') }} <!-- '' → 'Нет описания' -->
{{ user.tags | default(['новичок']) }} <!-- [] → ['новичок'] -->
{{ product.price | default('Цена не указана') }} <!-- 0 → 'Цена не указана' -->
{{ product.image | default('/no-image.png') }} <!-- null → '/no-image.png' -->
<!-- default_if_null - ТОЛЬКО для NULL значений -->
{{ user.nickname | default_if_null('Аноним') }} <!-- null → 'Аноним' -->
{{ user.bio | default_if_null('Нет описания') }} <!-- '' остается '' -->
{{ product.price | default_if_null(0) }} <!-- null → 0, false остается false -->
<!-- default_if_empty - ТОЛЬКО для пустых строк/массивов (НЕ null) -->
{{ user.bio | default_if_empty('Не указано') }} <!-- '' → 'Не указано' -->
{{ user.nickname | default_if_empty('Не указано') }} <!-- null остается null -->
{{ user.tags | default_if_empty(['общие']) }} <!-- [] → ['общие'] -->
<!-- Практические примеры -->
<div class="user-card">
<h3>{{ user.name }} ({{ user.nickname | default('без ника') }})</h3>
<img src="{{ user.avatar | default('/default-avatar.png') }}" alt="Аватар">
<p>{{ user.bio | default('Пользователь не добавил описание') }}</p>
</div>
Условное применение
<!-- Данные для примеров -->
{% set user = {
'role': 'admin',
'is_admin': true
} %}
{% set content = {
'text': '<p>Безопасный <b>HTML</b> контент</p>',
'trust_html': true
} %}
{% set sensitive_data = 'Секретная информация' %}
<!-- Условное применение фильтров (требует реализации в движке) -->
<!-- Показываем данные заглавными буквами только админам, остальным скрываем -->
{% if user.is_admin %}
{{ sensitive_data | upper }} <!-- СЕКРЕТНАЯ ИНФОРМАЦИЯ -->
{% else %}
{{ '***' }} <!-- *** -->
{% endif %}
<!-- Условное экранирование контента -->
{% if content.trust_html %}
{!! content.text !!} <!-- Выводим как HTML -->
{% else %}
{{ content.text | escape }} <!-- Экранируем HTML -->
{% endif %}
<!-- Альтернативный способ через тернарный оператор -->
{!! content.trust_html ? content.text : (content.text | escape) !!}
Специальные фильтры
JSON и сериализация
<!-- Данные для примеров -->
{% set user_data = {
'id': 123,
'name': 'Иван Петров',
'email': 'ivan@example.com',
'preferences': {
'theme': 'dark',
'language': 'ru'
}
} %}
{% set app_config = {
'api_url': 'https://api.example.com',
'timeout': 5000,
'features': ['auth', 'notifications', 'analytics']
} %}
<!-- JSON кодирование для использования в JavaScript -->
{{ user_data | json }}
<!-- Результат: {"id":123,"name":"Иван Петров","email":"ivan@example.com","preferences":{"theme":"dark","language":"ru"}} -->
<!-- Форматированный JSON (более читаемый) -->
<pre>{{ app_config | json }}</pre>
<!-- Результат (если поддерживает форматирование):
{
"api_url": "https://api.example.com",
"timeout": 5000,
"features": ["auth", "notifications", "analytics"]
} -->
<!-- Практическое использование в JavaScript -->
<script>
// Передача данных пользователя в JavaScript
var userData = {{ user_data | json }};
console.log('Пользователь:', userData.name);
// Передача конфигурации приложения
var config = {{ app_config | json }};
fetch(config.api_url + '/users/' + userData.id);
// Безопасная передача массивов
var features = {{ app_config.features | json }};
features.forEach(function(feature) {
console.log('Доступна функция:', feature);
});
</script>
Base64 и кодирование
<!-- Данные для примеров -->
{% set message = 'Привет, мир!' %}
{% set encoded_data = 'UHJpdmV0LCDQvNC40YAh' %} <!-- Base64 'Привет, мир!' -->
{% set search_params = 'поиск товаров & фильтры' %}
{% set callback_url = 'https://site.com/callback?param=значение&other=тест' %}
<!-- Base64 кодирование/декодирование -->
{{ message | base64_encode }} <!-- Результат: UHJpdmV0LCDQvNC40YAh -->
{{ encoded_data | base64_decode }} <!-- Результат: Привет, мир! -->
<!-- URL кодирование для безопасной передачи в параметрах -->
{{ search_params | urlencode }} <!-- Результат: поиск+товаров+%26+фильтры -->
{{ callback_url | urlencode }} <!-- Кодирование полного URL -->
<!-- URL декодирование -->
{{ 'поиск+товаров' | urldecode }} <!-- Результат: поиск товаров -->
<!-- Практические примеры -->
<!-- Скрытое поле с закодированными данными -->
<input type="hidden" name="data" value="{{ user_data | json | base64_encode }}">
<!-- Ссылка с параметром поиска -->
<a href="/search?q={{ search_query | urlencode }}">Поиск</a>
<!-- Redirect URL в параметрах -->
<a href="/login?redirect={{ current_url | urlencode }}">Войти</a>
Хеширование
<!-- Данные для примеров -->
{% set user = {
'email': 'ivan@example.com',
'id': 123
} %}
{% set sensitive_data = 'секретные данные пользователя' %}
{% set password = 'mypassword123' %}
<!-- MD5 хеш (не рекомендуется для паролей!) -->
{{ user.email | md5 }} <!-- Результат: MD5 хеш email -->
<!-- SHA1 хеш -->
{{ sensitive_data | sha1 }} <!-- Результат: SHA1 хеш данных -->
<!-- SHA256 хеш (рекомендуется) -->
{{ password | sha256 }} <!-- Результат: SHA256 хеш пароля -->
<!-- Практические применения -->
<!-- Уникальный ID на основе email -->
{% set user_hash = user.email | md5 %}
<div class="user-avatar" data-hash="{{ user_hash }}">
<!-- Можно использовать для Gravatar -->
<img src="https://www.gravatar.com/avatar/{{ user_hash }}" alt="Avatar">
</div>
<!-- Хеширование для кеширования -->
{% set cache_key = (user.id ~ user.email ~ 'profile') | sha1 %}
<!-- cache_key можно использовать как уникальный ключ кеша -->
Цепочки фильтров
Последовательная обработка
<!-- Данные для примеров -->
{% set user = {
'bio': ' Я веб-разработчик с большим опытом работы. Специализируюсь на создании современных приложений и изучении новых технологий. В свободное время читаю книги и занимаюсь спортом. \n\nТакже увлекаюсь фотографией.',
'first_name': ' иван ',
'last_name': ' петров '
} %}
{% set article = {
'title': 'как создать современное веб-приложение на php'
} %}
{% set product = {
'base_price': 1000,
'tax_rate': 0.2
} %}
<!-- Сложная обработка биографии пользователя -->
{{ user.bio | trim | truncate(100) | nl2br }}
<!-- Результат:
1. trim - убирает пробелы в начале и конце
2. truncate(100) - обрезает до 100 символов с "..."
3. nl2br - заменяет переносы строк на <br>
-->
<!-- Создание URL-friendly заголовка статьи -->
{{ article.title | lower | replace(' ', '-') | replace('[^a-zа-я0-9-]', '') }}
<!-- Результат: как-создать-современное-веб-приложение-на-php -->
<!-- Расчет и форматирование цены с налогом -->
{% set final_price = product.base_price * (1 + product.tax_rate) %}
{{ final_price | round(2) | money('₽') }}
<!-- Результат: ₽1,200.00 (1000 * 1.2 = 1200, округлено и отформатировано) -->
<!-- Форматирование полного имени -->
{{ (user.first_name | trim | title) ~ ' ' ~ (user.last_name | trim | title) }}
<!-- Результат: Иван Петров -->
Практические примеры
Карточка товара
<!-- Данные для примеров -->
{% set product = {
'name': 'Игровой ноутбук ASUS ROG Strix G15',
'description': '<p>Мощный игровой ноутбук с процессором AMD Ryzen 7 и видеокартой RTX 3060. Идеально подходит для современных игр и работы.</p><script>alert("xss");</script><p>Диагональ экрана 15.6 дюймов.</p>',
'price': 89999,
'sale_price': 74999,
'rating': 4.7,
'reviews_count': 156,
'category': {
'name': 'notebooks'
},
'tags': 'gaming, asus, laptop, rtx, amd,gaming,laptop',
'availability': 'in_stock'
} %}
<div class="product-card">
<!-- Заголовок товара: обрезаем до 50 символов, делаем красивым -->
<h3>{{ product.name | title | truncate(50) }}</h3>
<div class="price">
{% if product.sale_price %}
<!-- Цена со скидкой -->
<span class="sale">{{ product.sale_price | money('₽') }}</span>
<span class="original">{{ product.price | money('₽') }}</span>
<!-- Вычисляем процент скидки -->
{% set discount = ((product.price - product.sale_price) / product.price * 100) | round %}
<span class="discount">-{{ discount }}%</span>
<!-- Результат: Скидка 17% (89999-74999)/89999*100 = 16.67 ≈ 17 -->
{% else %}
<span class="price">{{ product.price | money('₽') }}</span>
{% endif %}
</div>
<!-- Описание: удаляем HTML теги, обрезаем до 20 слов -->
<p class="description">
{{ product.description | strip_tags | truncate_words(20) }}
</p>
<div class="meta">
<!-- Категория заглавными буквами -->
<span class="category">{{ product.category.name | upper }}</span>
<!-- Рейтинг с одним знаком после запятой -->
<span class="rating">
{{ product.rating | number(1) }}★
({{ product.reviews_count | number }} отзывов)
<!-- Результат: 4.7★ (156 отзывов) -->
</span>
</div>
<!-- Обработка тегов: разбиваем, чистим, убираем дубли, берем первые 3 -->
<div class="tags">
{% set formatted_tags = product.tags | split(',') | map('trim') | unique | slice(0, 3) %}
{% foreach formatted_tags as tag %}
<span class="tag">{{ tag | lower }}</span>
{% endforeach %}
<!-- Результат: gaming, asus, laptop -->
</div>
<!-- Статус доступности -->
<div class="availability">
{% set status_text = product.availability | replace('_', ' ') | title %}
<span class="status {{ product.availability }}">{{ status_text }}</span>
<!-- Результат: In Stock -->
</div>
</div>
Профиль пользователя
<!-- Данные для примеров -->
{% set user = {
'avatar': null,
'first_name': ' иван ',
'last_name': ' ПЕТРОВ ',
'username': 'IvanPetrov123',
'bio': 'Веб-разработчик со стажем более 5 лет.\n\nСпециализируюсь на PHP, JavaScript и современных фреймворках.\n\nВ свободное время изучаю новые технологии и читаю техническую литературу.',
'posts_count': 1247,
'followers_count': 5439,
'created_at': '2019-03-15 10:30:00',
'last_seen': '2024-01-15 14:25:00',
'email': 'ivan.petrov@example.com',
'location': 'москва, россия'
} %}
<div class="user-profile">
<div class="avatar">
<!-- Используем Gravatar или дефолтный аватар -->
{% set avatar_url = user.avatar | default('https://www.gravatar.com/avatar/' ~ (user.email | md5) ~ '?d=mp&s=200') %}
<img src="{{ avatar_url }}"
alt="Аватар пользователя {{ user.username | escape }}">
</div>
<div class="info">
<!-- Форматируем полное имя: убираем пробелы, делаем красивым -->
{% set full_name = (user.first_name | trim | title) ~ ' ' ~ (user.last_name | trim | title) %}
<h2>{{ full_name | trim }}</h2> <!-- Результат: Иван Петров -->
<!-- Username в нижнем регистре -->
<p class="username">@{{ user.username | lower }}</p>
{% if user.bio %}
<div class="bio">
<!-- Биография: переносы строк в br, обрезаем до 200 символов -->
{{ user.bio | nl2br | truncate(200) }}
</div>
{% endif %}
<!-- Локация с красивым форматированием -->
{% if user.location %}
<p class="location">📍 {{ user.location | title }}</p>
<!-- Результат: 📍 Москва, Россия -->
{% endif %}
<div class="stats">
<!-- Форматируем большие числа -->
<div class="stat">
<span class="number">{{ user.posts_count | number }}</span>
<span class="label">{{ user.posts_count | pluralize('пост', 'поста', 'постов') }}</span>
</div>
<div class="stat">
<span class="number">{{ user.followers_count | number }}</span>
<span class="label">{{ user.followers_count | pluralize('подписчик', 'подписчика', 'подписчиков') }}</span>
</div>
</div>
<div class="meta">
<!-- Дата регистрации -->
<p class="joined">
📅 Регистрация: {{ user.created_at | date('d.m.Y') }}
<!-- Результат: 📅 Регистрация: 15.03.2019 -->
</p>
{% if user.last_seen %}
<p class="last-seen">
<!-- Показываем когда был в последний раз -->
🕐 Последняя активность: {{ user.last_seen | date('d.m.Y H:i') }}
<!-- Результат: 🕐 Последняя активность: 15.01.2024 14:25 -->
</p>
{% endif %}
</div>
<!-- Контактная информация (частично скрытая) -->
<div class="contact">
{% set masked_email = user.email | replace('@', '***@') %}
<p class="email">✉️ {{ masked_email }}</p>
<!-- Результат: ✉️ ivan.petrov***@example.com -->
</div>
</div>
</div>
Следующий шаг: Изучите функции MNRFY.