Основы шаблонизатора 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 %}

Что происходит при наследовании

  1. Шаблонизатор загружает родительский макет
  2. Находит все блоки block в наследующем шаблоне
  3. Заменяет соответствующие блоки в родительском макете
  4. Весь остальной код в наследующем шаблоне игнорируется

Компоненты

<!-- 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 %}

Производительность

Кеширование шаблонов

Шаблоны автоматически компилируются и кешируются. В режиме отладки кеш обновляется автоматически при изменении файлов.

Оптимизация

Лучшие практики

  1. Разделение ответственности - логика в обработчиках, представление в шаблонах
  2. Безопасность - всегда используйте экранированный вывод для пользовательских данных
  3. Читаемость - используйте комментарии для сложных участков
  4. Переиспользование - выносите повторяющиеся элементы в компоненты
  5. Локализация - всегда используйте t() для текстов
Следующий шаг: Изучите работу с переменными и выводом данных.