Виды и шаблоны

Виды и шаблоны

Разделение забот

Пользовательский интерфейс, такой как HTML-страница, должен быть независим от базового PHP-кода, связанного с маршрутизацией и бизнес-логикой. Это фундаментально для парадигмы MVC. Базовая ревизия, такая как преобразование <h3>в<p>, не должна требовать изменения кода вашего приложения. Точно так же преобразование простого маршрута типа GET /aboutto GET /about-usне должно оказывать никакого влияния на ваш пользовательский интерфейс и бизнес-логику (представление и модель в MVC или представление и метод в RMR).

Смешивание программных конструкций и компонентов пользовательского интерфейса в одном файле, как спагетти-кодирование, делает будущее обслуживание приложений кошмаром.

PHP как шаблонный движок

F3 поддерживает PHP в качестве шаблонного движка. Взгляните на этот HTML фрагмент сохраненный какtemplate.htm:

<p>Hello, <?php echo $name; ?>!</p>

Независимо от того, включены ли короткие теги на вашем сервере или нет, это тоже должно работать:

<p>Hello, <?= $name ?></p>

Следующий PHP код использует этот Viewкласс для визуализации шаблона PHP хранящегося в template.htmфайле:

$f3=require('lib/base.php');
$f3->route('GET /',
    function($f3) {
        $f3->set('name','world');
        $view=new View;
        echo $view->render('template.htm');
        // Предыдущие две строки можно сократить до:
        // echo View::instance()->render('template.htm');
    }
);
$f3->run();

Единственная проблема с использованием PHP в качестве шаблонного движка, из-за встроенного PHP-кода в эти файлы, заключается в сознательном усилии, необходимом для того, чтобы придерживаться рекомендаций по разделению проблем и противостоять искушению смешивать бизнес-логику с вашим пользовательским интерфейсом.

Быстрый взгляд на язык шаблонов F3

В качестве альтернативы шаблонам PHP вы можете использовать собственный шаблонный движок F3 с этим Templateклассом. Приведенный выше фрагмент HTML может быть переписан следующим образом:

<p>Hello, {{ @name }}!</p>

и код, необходимый для просмотра этого шаблона:

$f3=require('lib/base.php');
$f3->route('GET /',
    function($f3) {
        $f3->set('name','world');
        echo \Template::instance()->render('template.htm');
    }
);
$f3->run();

Обратите внимание: Рекомендуемый синтаксис\Template::instance(). Тем не менее вы также можете создать новый экземпляр с new \Template();.

Например, маркеры маршрутизации, используемые для перехвата переменных в URL-адресах (все еще помните GET /brew/@countпример в предыдущем разделе?), Маркеры шаблона F3 начинаются с @символа, за которым следует ряд букв и цифр, заключенных в фигурные скобки. Первый символ должен быть альфа. Шаблонные токены имеют однозначное соответствие с переменными фреймворка. Фреймворк автоматически заменяет токен значением, хранящимся в переменной с тем же именем.

В нашем примере F3 заменяет @nameмаркер в нашем шаблоне значением, присвоенным переменной name. Во время выполнения вывод вышеприведенного кода будет выглядеть следующим образом::

<p>Hello, world</p>

Беспокоитесь о производительности шаблонов F3? Во время выполнения фреймворк анализирует и компилирует/преобразует шаблон F3 в PHP-код при первом его отображении $template->render(). Затем фреймворк использует этот скомпилированный код во всех последующих вызовах. Следовательно, производительность должна быть такой же, как и у шаблонов PHP, если не лучше из-за оптимизации кода, выполняемой компилятором шаблонов, когда задействованы более сложные шаблоны.

Независимо от того, используете ли вы движок шаблонов PHP или собственный движок F3, рендеринг шаблонов может быть значительно быстрее, если у вас есть APC, WinCache или XCache, доступные на вашем сервере.

Как упоминалось ранее, переменные фреймворка могут содержать любой тип данных PHP. Однако использование нескалярных типов данных в шаблонах F3 может привести к странным результатам, если вы не будете осторожны. Выражения в фигурных скобках всегда будут вычисляться и преобразовываться в строку. Вы должны ограничить переменные пользовательского интерфейса простыми скалярами:string,integer, booleanили floatтипами данных.

Но как насчет массивов? Fat-Free распознает массивы, и вы можете использовать их в своих шаблонах. Вы можете иметь что-то вроде:

<p>{{ @buddy[0] }}, {{ @buddy[1] }}, and {{ @buddy[2] }}</p>

И заполните @buddyмассив в вашем PHP коде перед подачей шаблона:

$f3->set('buddy',array('Tom','Dick','Harry'));

Однако, если вы просто вставите {{ @buddy }}его в свой шаблон, PHP сгенерирует Array to string conversionуведомление во время выполнения.

F3 позволяет вставлять выражения в шаблоны. Эти выражения могут принимать различные формы, такие как арифметические вычисления, булевы выражения, константы PHP и т. д. Вот несколько примеров:

{{ 2*(@page-1) }}
{{ (int)765.29+1.2e3 }}
<option value="F" {{ @active?'selected="selected"':'' }}>Female</option>
{{ var_dump(@xyz) }}
<p>That is {{ preg_match('/Yes/i',@response)?'correct':'wrong' }}!</p>
{{ @obj->property }}

Дополнительное замечание о выражениях массива: обратите внимание, что @foo.@barэто конкатенация строк ($foo.$bar), тогда @foo.barкак переводится $foo['bar']в. Если $foo[$bar]это то, что вы намеревались, используйте @foo[@bar]обычную нотацию.

Переменные фреймворка также могут содержать анонимные функции:

$f3->set('func',
    function($a,$b) {
        return $a.', '.$b;
    }
);

Механизм шаблонов F3 интерпретирует маркер как ожидалось, если вы зададите следующее выражение:

{{ @func('hello','world') }}

Обратите внимание: Если у вас есть ошибка неопределенной переменной или неопределенного индекса во время рендеринга ваших шаблонов F3, это означает, что переменная или индекс массива ранее не были объявлены в вашей функции, вызывающей действие template render (). Два решения:

  • Предпочтительно: определите все переменные в вашем коде, даже если они равны нулю;

    • $f3 - >set ('myVar', NULL)

    • $f3 - >set ('myArray.myIndex', 'первый пункт')

  • Быстро, но грязно: используйте дополнительный символ AT @ перед токеном;

    • {{@@myArray.myIndex}}

    • чтобы подавить отображение сообщения об ошибке

Для получения более подробной информации обратитесь к выпуску FatFree GitHub #201.

Шаблоны Внутри Шаблонов

Простая замена переменных-это то, что есть у всех шаблонных движков. F3 имеет больше в рукавах:

<include href="header.htm" />

Директива будет встраивать содержимое заголовка шаблон htm находится в точном месте, где указана директива. Вы также можете иметь динамический контент в виде:

<include href="{{ @content }}" />
// ИЛИ
<include href="{{ 'templates/layout/'.@content }}" />

// НЕПРАВИЛЬНО
<include href="templates/layout/{{ @content }}" />

Практическая польза для такой директивы шаблона заключается в том, что у вас есть несколько страниц с общим HTML-макетом, но с разным контентом. Указание фреймворку вставить подшаблон в ваш основной шаблон так же просто, как написать следующий PHP-код:

// переключите контент на подшаблон вашего блога
$f3->set('content','blog.htm');
// в другом маршруте переключите содержимое на подшаблон wiki
$f3->set('content','wiki.htm');

Подшаблон, в свою очередь, может содержать любое количество директивы. F3 позволяет использовать неограниченное количество вложенных шаблонов.

Вы можете указать имена файлов с чем-то другим, чем .htm или .расширения html-файлов, но их проще просматривать в вашем веб-браузере на этапе разработки и отладки. Механизм шаблонов не ограничивается рендерингом HTML-файлов. На самом деле вы можете использовать механизм шаблонов для визуализации других типов файлов.

<include>Директива имеет необязательный ifатрибут, позволяющий указать условие, которое должно быть выполнено для вставки подшаблона:

<include if="{{ count(@items) >= 2 }}" href="items.htm" />

Текущий массив данных передается в подшаблон. Однако вы можете передавать новые переменные или перезаписывать существующие переменные с помощью withатрибута:

<!-- передайте $a=2 в sub.htm -->
<include href="sub.htm" with="a=2" />

<!-- передайте $b="что-то" и $c= "что-то в кавычках" sub.htm -->
<include href="sub.htm" with="b=something,c='something quoted'" />

<!-- передайте значение в верхнем регистре $d в sub.htm -->
<set d="abc" />
<include href="sub.htm" with="d={{strtoupper($d)}}" /> // $d='ABC'
{{@d}} // $d='abc'

Обратите внимание: в настоящее время невозможно использовать PHPTRUE-константу как с-переменную, так как все атрибуты анализируются как строка.

Исключение сегментов

Во время написания/отладки программ на базе F3 и разработки шаблонов могут быть случаи, когда отключение отображения блока HTML может оказаться полезным. Вы можете использовать <exclude>директиву для этой цели:

<exclude>
    <p>Кусок HTML, который мы не хотим отображать в данный момент</p>
</exclude>

Это похоже на <!-- comment -->тег HTML-комментария, но <exclude>директива делает HTML-блок полностью невидимым после рендеринга шаблона.

Вот еще один способ исключения содержимого шаблона или добавления комментариев:

{* <p>Кусок HTML, который мы не хотим отображать в данный момент</p> *}

Условные Сегменты

Еще одна полезная функция шаблона-<check>директива. Он позволяет встраивать HTML-фрагмент в зависимости от оценки определенного условия. Вот несколько примеров:

<check if="{{ @page=='Home' }}">
    <false><span>Вставляется, если условие ложно</span></false>
</check>
<check if="{{ @gender=='M' }}">
    <true>
        <div>Появляется, когда условие истинно</div>
    </true>
    <false>
        <div>Появляется, когда условие ложно</div>
    </false>
</check>

Вы можете иметь столько вложенных <check>директив, сколько вам нужно.

Выражение F3 внутри атрибута if, которое приравнивается к NULLпустой строке, логическому FALSEзначению, пустому массиву или нулю, автоматически вызывается <false>. Если ваш шаблон не имеет <false>блока, то <true>открывающие и закрывающие теги являются необязательными:

<check if="{{ @loggedin }}">
    <p>Фрагмент HTML, который будет включен, если условие истинно</p>
</check>

Повторяющиеся Сегменты

Fat-Free также может обрабатывать повторяющиеся HTML-блоки:

<repeat group="{{ @fruits }}" value="{{ @fruit }}">
    <p>{{ trim(@fruit) }}</p>
</repeat>

groupАтрибут @fruitsвнутри <repeat>директивы должен быть массивом и должен быть установлен в вашем PHP коде соответствующим образом:

$f3->set('fruits',array('apple','orange ',' banana'));

Присвоение значения @fruitв коде приложения ничего не дает. Fat-Free игнорирует любое заданное значение, которое у него может быть, потому что он использует переменную для представления текущего элемента во время итерации по группе. Вывод приведенного выше фрагмента HTML шаблона и соответствующего PHP кода становится:

<p>apple</p>
<p>orange</p>
<p>banana</p>

Фреймворк допускает неограниченную вложенность <repeat>блоков:

<repeat group="{{ @div }}" key="{{ @ikey }}" value="{{ @idiv }}">
    <div>
        <p><span><b>{{ @ikey }}</b></span></p>
        <p>
        <repeat group="{{ @idiv }}" value="{{ @ispan }}">
            <span>{{ @ispan }}</span>
        </repeat>
        </p>
    </div>
</repeat>

Примените следующую команду F3:

$f3->set('div',
    array(
        'coffee'=>array('arabica','barako','liberica','kopiluwak'),
        'tea'=>array('darjeeling','pekoe','samovar')
    )
);

В результате вы получаете следующий HTML-фрагмент:

<div>
    <p><span><b>coffee</b></span></p>
    <p>
        <span>arabica</span>
        <span>barako</span>
        <span>liberica</span>
        <span>kopiluwak</span>
    <p>
</div>
<div>
    <p><span><b>tea</b></span></p>
    <p>
        <span>darjeeling</span>
        <span>pekoe</span>
        <span>samovar</span>
    </p>
</div>

Удивительно, не правда ли? И единственное, что вам нужно было сделать в PHP, - это определить содержимое одной переменной F3div, чтобы заменить @divтокен. Fat-Free делает как программирование, так и дизайн веб-шаблонов действительно простыми.

Атрибут <repeat>директивы template valueвозвращает значение текущего элемента в итерации. Если вам нужно получить ключ массива текущего элемента, используйте keyвместо него атрибут. keyАтрибут необязателен.

<repeat> также имеет необязательный атрибут счетчика, который можно использовать следующим образом:

<repeat group="{{ @fruits }}" value="{{ @fruit }}" counter="{{ @ctr }}">
    <p class="{{ @ctr%2?'odd':'even' }}">{{ trim(@fruit) }}</p>
</repeat>

Внутренне механизм шаблонов F3 записывает количество итераций цикла и сохраняет это значение в переменной/токене @ctr, которая используется в нашем примере для определения нечетной/четной классификации.

Встраивание Javascript и CSS

Если вам нужно вставить маркеры F3 внутри <script><style>раздела или вашего шаблона, фреймворк все равно заменит их обычным способом:

<script type="text/javascript">
    function notify() {
        alert('Вы вошли в систему как: {{ @userID }}');
    }
</script>

Встраивание директив шаблонов в ваши <script><style>теги or не требует специальной обработки:

<script type="text/javascript">
	var discounts=[];
    <repeat group="{{ @rates }}" value="{{ @rate }}">
        // все, что вы хотите повторить в Javascript, например
        discounts.push("{{ @rate }}");
    </repeat>
</script>

Пути к файлам

Есть некоторые вещи, которые следует учитывать в отношении общедоступных путей, используемых в ссылках на страницы или стилях / сценариях или изображениях. Вероятно, вы хотите использовать относительные пути:

<link href="ui/css/base.css" type="text/css" rel="stylesheet" />
<script src="ui/js/base.css"></script>
<a href="category-abc/article-xyz">подробнее</a>
<img src="ui/img/img1.jpg" alt="Image 1" />

Эти пути могут работать на вашей индексной странице GET /, но вызовут проблемы при переходе к GET /@category/@articleприложению или запуске приложения из подкаталога в общедоступном корневом каталоге вашего веб-пространства (http://domain.com/my-F3-App/т. е. Чтобы решить эту проблему, вы должны либо дополнить все свои пути общедоступным базовым путем, как это:

<link href="{{@BASE}}/ui/css/base.css" type="text/css" rel="stylesheet" />
<script src="{{@BASE}}/ui/js/base.css"></script>
<a href="{{@BASE}}/category-abc/article-xyz">подробнее</a>
<img src="{{@BASE}}/ui/img/img1.jpg" alt="Image 1" />

Или используйте базовый тег HTML, чтобы указать базовый путь по умолчанию для всех документов для относительных ссылок:

<base href="{{@SCHEME.'://'.@HOST.@BASE.'/'}}">

Есть некоторые побочные эффекты использования <base>тега в вашем документе: в основном вам также нужно префиксить все якорные ссылки страниц (<a href="{{@PATH}}#top">go to top</a>).

Кодировка Документа

Fat-Free по умолчанию использует набор символов UTF-8. Вы можете переопределить это поведение, установив ENCODINGсистемную переменную следующим образом:

$f3->set('ENCODING','ISO-8859-1');

Как только вы сообщите фреймворку желаемый набор символов, F3 будет использовать его для всех HTML-и XML-шаблонов, пока снова не изменит их.

Все виды шаблонов

Как уже упоминалось ранее в этом разделе, фреймворк не ограничивается HTML-шаблонами. Вы также можете обрабатывать XML-шаблоны. Механика в значительной степени схожа. В вашем распоряжении все те же {{ @variable }}{{ expression }}жетоны, <repeat>, <check>, <include>, и <exclude>директивы. Просто скажите F3, что вы передаете XML-файл вместо HTML:

echo Template::instance()->render('template.xml','application/xml');

Второй аргумент представляет тип MIME отображаемого документа.

Компонент представления MVC охватывает все, что не подпадает под модель и контроллер, а это означает, что ваша презентация может и должна включать в себя все виды пользовательских интерфейсов, таких как RSS, электронная почта, RDF, FOAF, текстовые файлы и т. д. В приведенном ниже примере показано, как отделить презентацию электронной почты от бизнес-логики приложения:

MIME-Version: 1.0
Content-type: text/html; charset={{ @ENCODING }}
From: {{ @from }}
To: {{ @to }}
Subject: {{ @subject }}

<p>Добро пожаловать и спасибо, что присоединились {{ @site }}!</p>

Сохраните вышеприведенный шаблон электронной почты как приветствие формат txt. Связанный с этим код F3 будет следующим:

$f3->set('from','<no-reply@mysite.com>');
$f3->set('to','<slasher@throats.com>');
$f3->set('subject','Welcome');
ini_set('sendmail_from',$f3->get('from'));
mail(
    $f3->get('to'),
    $f3->get('subject'),
    Template::instance()->render('email.txt','text/html')
);

Совет: замените функцию SMTP mail() на imap_mail (), если ваш скрипт взаимодействует с сервером IMAP.

Ну разве это не здорово? Конечно, если у вас есть набор получателей электронной почты, вы будете использовать базу данных для заполнения маркеров firstName, lastName и email.

Вот альтернативное решение, использующее SMTP-плагин F3:

$mail=new SMTP('smtp.gmail.com',465,'SSL','account@gmail.com','secret');
$mail->set('from','<no-reply@mysite.com>');
$mail->set('to','"Slasher" <slasher@throats.com>');
$mail->set('subject','Welcome');
$mail->send(Template::instance()->render('email.txt'));

многоязычная поддержка

F3 поддерживает несколько языков прямо из коробки.

Сначала создайте файл словаря со следующей структурой (по одному файлу на каждый язык):

<?php
return array(
    'love'=>'I love F3',
    'today'=>'Today is {0,date}',
    'pi'=>'{0,number}',
    'money'=>'Amount remaining: {0,number,currency}'
);

Сохраните его как dict/en.php. Давайте создадим еще один словарь, на этот раз для немецкого языка. Сохраните файл какdict/de.php:

<?php
return array(
    'love'=>'Ich liebe F3',
    'today'=>'Heute ist {0,date}',
    'money'=>'Restbetrag: {0,number,currency}'
);

Словари - это не более чем пары ключ-значение. F3 автоматически создает экземпляры переменных фреймворка на основе ключей в языковых файлах. Таким образом, легко встроить эти переменные в качестве маркеров в ваши шаблоны.

Обратите внимание: пары ключ-значение словаря становятся переменными F3 после ссылки. Убедитесь, что ключи не конфликтуют ни с одной переменной фреймворка, созданной с помощью `$f3->set ()`, `$f3->>mset ()` или `$f3->>>config()`. Кроме того, вы также можете использовать префикс var для установки общего ключа, который предшествует каждому языковому ключу.

Примеры использования нескольких языков с помощью движка шаблонов F3:

<h1>{{ @love }}</h1>
<p>
    {{ @today,time() | format }}.<br />
    {{ @money,365.25 | format }}<br />
    {{ @pi, 3.1415 | format }}
</p>

И более длинная версия, которая использует PHP в качестве шаблонного движка:

<?php $f3=Base::instance(); ?>
<h1><?php echo $f3->get('love'); ?></h1>
<p>
    <?php echo $f3->get('today',time()); ?>.<br />
    <?php echo $f3->get('money',365.25); ?><br />
    <?php echo $f3->get('pi', 3.1415); ?>
</p>

Далее мы даем команду F3 искать словари в dict/папке:

$f3->set('LOCALES','dict/');

Но как фреймворк определяет, какой язык использовать? F3 обнаружит его автоматически, посмотрев сначала на заголовки HTTP-запросов, а именно на Accept-Languageзаголовок, отправленный браузером.

Чтобы переопределить это поведение, можно вызвать F3 для использования языка, указанного пользователем или приложением:

$f3->set('LANGUAGE','de');

Основной язык вашего сайта

В приведенном выше примере ключ piсуществует только в словаре английского языка. Фреймворк всегда будет использовать резервный язык для заполнения ключей, которые отсутствуют в указанном или обнаруженном языке(языках). В нашем примере ключpi, присутствующий в словаре английского языка, был выбран потому, что английский язык является резервным языком по умолчанию, установленным F3 при запуске. Поэтому важно убедиться, что все многоязычные тексты, используемые на вашем сайте, определены в словаре резервного языка в противном случае во время выполнения будет вызвана ошибка или, по крайней мере, предупреждение или уведомление, когда будет сделана ссылка на неопределенную переменную.

Если основной язык вашего сайта не английский, и вы не перевели все строки на другие языки, вы должны поручить F3 использовать ваш справочник по родному языку в качестве запасного варианта. Вы можете легко сделать это благодаря переменной FALLBACKhive:

$f3->set('FALLBACK','it');  // Итальянский как запасной язык по умолчанию

Варианты Языка

Вы также можете создавать файлы словарей для языковых вариантов, таких какen-US,es-AR, и т.д. В этом случае F3 сначала будет использовать языковой вариант, например es-AR. Если есть ключи, которые не существуют в словаре вариантов, фреймворк будет искать ключ в корневом языке , напримерes, и, если он все еще не найден, использовать определенный резервный языковой файл.

Вы заметили странную 'Today is {0,date}'закономерность в нашем предыдущем примере? Многоязычная возможность F3 зависит от правил форматирования строк/сообщений проекта ICU. Фреймворк использует свое собственное подмножество реализации форматирования строк ICU. Нет никакой необходимости в intlтом, чтобы расширение PHP было активировано на сервере.

Еще одна вещь: F3 также может загружаться .файлы в формате ini-style в виде словарей:

love = Я люблю F3
today = Сегодня {0,date}
pi = {0,number}
money = Оставшаяся сумма: {0,number,currency}
multiline = Также возможно наличие языковых клавиш \
            распределено по нескольким линиям

[module.user.validation]
name.required = Пожалуйста, введите свое имя.
mail.invalid = Этот адрес электронной почты недействителен.

Сохраните его как dict/en.iniтаковой, чтобы фреймворк мог загружать его автоматически. Языковая переменная принимает тот же тип строки, что и заголовок HTTP Accept-Language, который представляет собой разделенный запятыми список 2-буквенных кодов языков, за которыми необязательно следует дефис и 2-буквенный код страны. NB: несмотря на то, что локали POSIX используют подчеркивание в качестве разделителя (es_BR.UTF-8), вы должны определить языковую переменную с дефисом (es-BR). Файлы словарей следуют тому же правилу (es-BR.php / es-BR.ini).

Дополнительные технические сведения см. В разделе База->язык> метод.

Санитария Данных

По умолчанию и обработчик представлений, и механизм шаблонов экранируют все визуализированные переменные, то есть преобразуются в HTML-сущности, чтобы защитить вас от возможных атак XSS и инъекций кода. С другой стороны, если вы хотите передать допустимые HTML-фрагменты из кода приложения в шаблон:

$f3->set('ESCAPE',FALSE);

Это может иметь нежелательные последствия. Возможно, вы не захотите, чтобы все переменные проходили через unescaped. Fat-Free позволяет вам распаковывать переменные по отдельности. Для шаблонов F3 используйте rawфильтр:

{{ @html_content | raw }}

В случае PHP-шаблонов используйте непосредственно raw-метод:

<?php echo $this->raw($html_content); ?>

В дополнение к автоматическому экранированию переменных F3 фреймворк также дает вам свободу действий при очистке пользовательского ввода из HTML-форм:

$f3->scrub($_GET,'p; br; span; div; a');

Эта команда удалит все теги (кроме указанных во втором аргументе) и небезопасные символы из указанной переменной. Если переменная содержит массив, то каждый элемент в массиве рекурсивно очищается. Если звездочка ( * ) передается в качестве второго аргумента, $f3->scrub()это позволяет всем HTML-тегам проходить через нетронутые и просто удалять небезопасные управляющие символы.

Расширение фильтров и пользовательских тегов

С помощью шаблонного движка F3 вы также можете настроить собственные фильтры выражений like{{ @desc,100 | crop }}, а также комбинировать их like {{ @desc,100 | crop,raw }}. Поэтому вам просто нужно зарегистрировать новый фильтр с помощью метода filter. Для собственных обработчиков html-тегов / элементов, которые могут отображать все, что вы хотите, проверьте метод template->extend>. Для получения более подробных описаний пользовательских фильтров и работы всей системы шаблонов см. расширенную часть руководства пользователя по шаблону.

Last updated