Основы шаблонизатора MNRFY
Изучите синтаксис и базовые концепции шаблонизатора MNRFY
Введение
Шаблонизатор MNRFY основан на проверенных концепциях Twig, но имеет собственные расширения и оптимизации. Он обеспечивает чистое разделение логики представления и бизнес-логики.
Базовый синтаксис
Три основных типа разметки
| Синтаксис | Назначение | Пример |
|---|---|---|
{{ }} |
Вывод данных (экранированный) | {{ user.name }} |
{!! !!} |
Вывод данных (сырой HTML) | {!! article.content !!} |
{% %} |
Управляющие конструкции | {% if user %} ... {% endif %} |
{# #} |
Комментарии | {# Это комментарий #} |
Простейший пример
<!DOCTYPE html>
<html>
<head>
<title>{{ config('app.name') }}</title>
</head>
<body>
{# Это комментарий - не будет отображаться #}
<h1>Добро пожаловать!</h1>
{% if user %}
<p>Привет, {{ user.name }}!</p>
{% else %}
<p>Привет, гость!</p>
{% endif %}
<div class="content">
{!! page.content !!}
</div>
</body>
</html>
Вывод данных
Экранированный вывод Безопасно
<!-- Автоматически экранирует HTML -->
{{ user.name }}
{{ post.title }}
{{ comment.text }}
<!-- Результат: <script> будет показано как текст -->
{{ "<script>alert('XSS')</script>" }}
Сырой вывод Осторожно
<!-- НЕ экранирует HTML - только для доверенных данных! -->
{!! article.content !!}
{!! page.html_content !!}
<!-- Результат: HTML будет выполнен -->
{!! "<strong>Жирный текст</strong>" !!}
Предупреждение: Никогда не используйте
{!! !!} для пользовательских данных! Это может привести к XSS атакам.
Доступ к переменным
Простые переменные
{{ title }}
{{ message }}
{{ count }}
Свойства объектов
{{ user.name }}
{{ user.email }}
{{ user.profile.avatar }}
Элементы массивов
{{ items[0] }}
{{ menu['home'] }}
{{ menu["home"] }}
{{ data.user.id }}
{{ data['user']['id'] }}
Элементы массивов - Разнообразные примеры по использованию
{% set test_array1 = {"name":"Данило"} %}
{% set test_array2 = ["Данило"] %}
{% set test_array3 = {"danilo":{"name":"Данило"}} %}
{% set test_array4 = {"danilo":["Данило"]} %}
<p>1 - {{ test_array1["name"] }}</p>
<p>2 - {{ test_array1['name'] }}</p>
<p>3 - {{ test_array1.name }}</p>
<p>4 - {{ test_array2[0] }}</p>
<p>5 - {{ test_array3.danilo.name }}</p>
<p>6 - {{ test_array3["danilo"]["name"] }}</p>
<p>7 - {{ test_array3['danilo']["name"] }}</p>
<p>8 - {{ test_array3["danilo"]['name'] }}</p>
<p>9 - {{ test_array3.danilo.name }}</p>
<p>10 - {{ test_array3["danilo"].name }}</p>
<p>11 - {# test_array3.danilo[name] - не выводит. ошибка - Invalid property name #}</p>
<p>12 - {# test_array3.danilo["name"] - не выводит. ошибка - Invalid property ["name"] #}</p>
<p>13 - {# test_array3.danilo['name'] - не выводит. ошибка - Invalid property ['name'] #}</p>
<p>14 - {# test_array3[danilo.name] - не выводит. ошибка - Undefined constant "danilo" #}</p>
<p>15 - {# test_array4.danilo[0] - не выводит. ошибка - Invalid property name: danilo[0] #}</p>
<p>16 - {# test_array4[danilo][0] - не выводит. ошибка - Undefined constant "danilo" #}</p>
<p>17 - {{ test_array4['danilo'][0] }}</p>
<p>18 - {{ test_array4["danilo"][0] }}</p>
Вызов методов
{% php %}
function test(){
return "Hello Function!";
}
{% endphp %}
{{ test() }}
Комментарии
{# Однострочный комментарий #}
{#
Многострочный
комментарий
для документирования
#}
{# TODO: Добавить проверку прав доступа #}
Форматирование
Многострочные выражения
<!-- Можно разбивать на несколько строк -->
{{ test_word
~ ' (' ~ user.name ~ ')'
}}
{% if
i_true()
%}
Доступ разрешен
{% endif %}
Многострочные выражения (Более полный пример)
{% set test_word = "Welcome " %}
{% php %}
function i_true(){
return true;
}
function i_false(){
return false;
}
{% endphp %}
{{ test_word
~ ' (' ~ user.name ~ ')'
}}
{% if
i_true()
%}
Доступ разрешен
{% endif %}
Наследование шаблонов
Базовый макет
<!-- layouts/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
{% block meta %}{% endblock %}
{% block styles %}
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
{% endblock %}
</head>
<body>
<header>
{% block header %}
<h1>{{ config('app.name') }}</h1>
{% endblock %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}
<p>© {{ date('Y') }} Все права защищены</p>
{% endblock %}
</footer>
{% block scripts %}{% endblock %}
</body>
</html>
Наследующий шаблон
<!-- about.html -->
{% extends 'layouts/base.html' %}
<!-- ❌ НЕПРАВИЛЬНО: этот код будет проигнорирован! -->
<p>Этот текст не будет отображен</p>
<div>И этот блок тоже не покажется</div>
{% block title %}О компании - {{ parent() }}{% endblock %}
{% block meta %}
{{ parent() }}
<meta name="description" content="Информация о нашей компании">
{% endblock %}
<!-- ❌ НЕПРАВИЛЬНО: код вне блоков игнорируется -->
<script>console.log('Этот скрипт не выполнится');</script>
{% block content %}
<!-- ✅ ПРАВИЛЬНО: весь контент должен быть внутри блоков -->
<h2>О нашей компании</h2>
<p>Мы работаем уже {{ years }} лет...</p>
{% endblock %}
{% block scripts %}
<!-- ✅ ПРАВИЛЬНО: скрипты в соответствующем блоке -->
<script>console.log('Этот скрипт выполнится!');</script>
{% endblock %}
Распространенная ошибка! Новички часто пытаются писать HTML код вне блоков в наследующих шаблонах. Запомните: при использовании
extends обрабатываются только блоки block.
Правильная структура наследующего шаблона
<!-- ✅ ПРАВИЛЬНАЯ структура -->
{% extends 'layouts/base.html' %}
{% block title %}Заголовок страницы{% endblock %}
{% block styles %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/page-specific.css') }}">
{% endblock %}
{% block content %}
<div class="page-content">
<h1>Содержимое страницы</h1>
<p>Весь контент должен быть внутри блоков</p>
</div>
{% endblock %}
{% block scripts %}
{{ parent() }}
<script src="{{ asset('js/page-specific.js') }}"></script>
{% endblock %}
Что происходит при наследовании
- Шаблонизатор загружает родительский макет
- Находит все блоки
blockв наследующем шаблоне - Заменяет соответствующие блоки в родительском макете
- Весь остальной код в наследующем шаблоне игнорируется
Компоненты
<!-- components/alert.html -->
<div class="alert alert-{{ type ?? 'info' }}">
{% if title %}
<h4>{{ title }}</h4>
{% endif %}
{{ message }}
</div>
<!-- Использование компонента -->
{% component 'alert' with {
'type': 'success',
'title': 'Успех!',
'message': 'Данные сохранены'
} %}
Глобальные переменные
В любом шаблоне доступны следующие переменные:
| Переменная | Описание | Пример |
|---|---|---|
available_locales |
Все доступные на сайте языки | {{ available_locales }} |
main_locale |
Основной язык сайта | {{ main_locale }} |
userLocale |
Текущий язык юзера | {{ userLocale }} |
locale |
Текущий язык сайта | {{ locale }} |
interfaceLocale (local синоним) |
Текущий язык сайта | {{ interfaceLocale }} |
request |
Объект HTTP запроса | {{ request.path }} |
session |
Данные сессии | {{ session.flash_message }} |
Безопасность
Автоматическое экранирование
<!-- Безопасно - HTML будет экранирован -->
{{ user_input }}
<!-- Опасно - только для доверенных данных! -->
{!! admin_content !!}
CSRF защита
<form method="POST">
{{ csrf() }}
<!-- Остальные поля формы -->
</form>
Отладка
Вывод отладочной информации
<!-- Дамп переменной -->
{{ var_dump(available_locales) }}
<!-- Условная отладка -->
{% if config('app.debug') %}
<pre>{{ available_locales | json }}</pre>
{% endif %}
Производительность
Кеширование шаблонов
Шаблоны автоматически компилируются и кешируются. В режиме отладки кеш обновляется автоматически при изменении файлов.
Оптимизация
- Избегайте сложных вычислений в шаблонах
- Используйте кеширование для тяжелых запросов к БД
- Минимизируйте количество включаемых файлов
Лучшие практики
- Разделение ответственности - логика в обработчиках, представление в шаблонах
- Безопасность - всегда используйте экранированный вывод для пользовательских данных
- Читаемость - используйте комментарии для сложных участков
- Переиспользование - выносите повторяющиеся элементы в компоненты
- Локализация - всегда используйте
t()для текстов
Следующий шаг: Изучите работу с переменными и выводом данных.