Виды и шаблоны
Пользовательский интерфейс, такой как HTML-страница, должен быть независим от базового PHP-кода, связанного с маршрутизацией и бизнес-логикой. Это фундаментально для парадигмы MVC. Базовая ревизия, такая как преобразование
<h3>
в<p>
, не должна требовать изменения кода вашего приложения. Точно так же преобразование простого маршрута типа GET /about
to GET /about-us
не должно оказывать никакого влияния на ваш пользовательский интерфейс и бизнес-логику (представление и модель в MVC или представление и метод в RMR).Смешивание программных конструкций и компонентов пользовательского интерфейса в одном файле, как спагетти-кодирование, делает будущее обслуживание приложений кошмаром.
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-кода в эти файлы, заключается в сознательном усилии, необходимом для того, чтобы придерживаться рекомендаций по разделению проблем и противостоять искушению смешивать бизнес-логику с вашим пользовательским интерфейсом.
В качестве альтернативы шаблонам 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'
Обратите внимание: в настоящее время невозможно использовать PHP
TRUE
-константу как с-переменную, так как все атрибуты анализируются как строка.Во время написания/отладки программ на базе 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, - это определить содержимое одной переменной F3
div
, чтобы заменить @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
, которая используется в нашем примере для определения нечетной/четной классификации.Если вам нужно вставить маркеры 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 использовать ваш справочник по родному языку в качестве запасного варианта. Вы можете легко сделать это благодаря переменной
FALLBACK
hive:$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 modified 2yr ago