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

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

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

Пользовательский интерфейс, такой как 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}}
    • чтобы подавить отображение сообщения об ошибке

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

Простая замена переменных-это то, что есть у всех шаблонных движков. 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','<[email protected]>');
$f3->set('to','<[email protected]>');
$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','[email protected]','secret');
$mail->set('from','<[email protected]>');
$mail->set('to','"Slasher" <[email protected]>');
$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>. Для получения более подробных описаний пользовательских фильтров и работы всей системы шаблонов см. расширенную часть руководства пользователя по шаблону.