Подключаем шаблонизатор Fenom
Знаю-знаю, мы собирались работать на чистом PHP, безо всяких фреймворков, но о шаблонизаторах речи не было!
Если серьёзно, то я по всякому прикинул, как заставить наш простенький сайт выводить HTML, и не вписывать его в PHP, а хранить в шаблонах.
Варианта ровно два: написать собственный жуткий глючный велосипед, который будет читать шаблон и заменять в нём плейсхолдеры на значения через str_replace(), или подключить нормальный шаблонизатор.
Так как мы все тут от MODX люди не очень далёкие, так почему бы не освоить работу с Fenom, который в нём с некоторых пор доступен? Думаю, возражений не будет, так что поехали!
Зачем?
Для начала давайте определимся, зачем нам вообще нужен шаблонизатор? Можно же писать HTML прямо в PHP и выводить его через echo?
Можно, конечно. Но такой код будет очень сложно развивать и поддерживать, даже если вы работаете над ним в одиночку. А если с вами будет работать еще и дизайнер\верстальщик, то ему придётся выучить PHP и разобраться в вашем коде, чтобы вносить изменения.
Подключение же шаблонизатора позволит очень просто менять внешний вид сайта, используя его синтаксис. Знания PHP не нужны, а код и представление разделены.
Подключение
Идём в репозиторий Fenom и скачиваем свежий релиз.
Распаковываем архив и переносим всё из директории scr в нашу Core. Так как Fenom придерживается PSR, то свою директорию называет с большой буквы. Чтобы не ломать единообразие, переименуем и нашу директорию controllers в Controllers.
Заодно порадуемся тому факту, что путь к контроллерам у нас задан в конфиге класса Core под ключом controllersPath - указываем заглавную букву и там. Код на GitHub сейчас такой.
Теперь нам нужно как-то добавить работу с Fenom в наш класс Core. Пишем для этого отдельный метод getFenom():
public function getFenom() {
// Работаем только, если переменная класса пуста
if (!$this->fenom) {
// Пробуем загрузить шаблонизатор
// Все выброшенные исключения внутри этого блока будут пойманы в следующем
try {
// Подключаем класс загрузки
if (!class_exists('Fenom')) {
require 'Fenom.php';
// Регистрируем остальные классы его методом
Fenom::registerAutoload();
}
// Проверяем и создаём директорию для кэширования скомпилированных шаблонов
if (!file_exists($this->config['cachePath'])) {
mkdir($this->config['cachePath']);
}
// Запускаем Fenom
$this->fenom = Fenom::factory($this->config['templatesPath'], $this->config['cachePath'], $this->config['fenomOptions']);
}
// Ловим исключения, если есть, и отправляем их в лог
catch (Exception $e) {
$this->log($e->getMessage());
// Возвращаем false
return false;
}
}
// Возвращаем объект Fenom
return $this->fenom;
}
Здесь всё по инструкции от автора.
Как видите, загрузка Fenom происходит только один раз, потом Core будет отдавать уже инициализированный экземпляр. Также по коду видно, что добавились и новые параметры в настройки, и метод log(), для вывода ошибок.
Предлагаю всё это посмотреть вам на GitHub, вместе с нашим первым шаблоном в /Core/Templates/home.tpl:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Третий курс обучения на bezumkin.ru</title>
</head>
<body>
<h1>Привет, мир!</h1>
</body>
</html>
Который выводит контроллер Home:
public function run() {
// Метод getFenom() может вернуть или false, или объект
// Так что нужно проверять, что именно приходит
if ($fenom = $this->core->getFenom()) {
return $fenom->fetch('home.tpl');
}
else {
return '';
}
}
Скелет шаблонизации готов, можно работать дальше.
Шаблоны
Предлагаю теперь нам еще подключить Bootstrap для оформления страниц и нарисовать простейший шаблон, которым будут оформлены главная страница, и test.
Качаем последний Bootstrap, распаковывем и кладём в директорию /assets/. Вот состояние нашего репозитория с подключенным Bootstrap.
Дальше предусматриваем в шаблоне переменные Fenom, которые он потом заменит на полученные от контроллера значения:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{$pagetitle}</title>
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h3>{$longtitle ?: $pagetitle}</h3>
{$content}
</div>
</body>
<footer>
<script src="/assets/js/jquery-2.1.4.min.js"></script>
<script src="/assets/js/bootstrap.min.js"></script>
</footer>
</html>
После чего в контроллере Home меняем метод run() вот так:
public function run() {
if ($fenom = $this->core->getFenom()) {
return $fenom->fetch('home.tpl', array(
'pagetitle' => 'Тестовый сайт',
'longtitle' => 'Третий курс обучения',
'content' => 'Текст главной страницы курса обучения на bezumkin.ru',
));
}
else {
return '';
}
}
Как видите, наш шаблон уже умеет проверять longtitle на пустоту и подставлять вместо него pagetitle, если нужно. Пользуемся этим в методе run() контроллера Test:
public function run() {
if ($fenom = $this->core->getFenom()) {
return $fenom->fetch('home.tpl', array(
'pagetitle' => 'Тестовая страница',
'longtitle' => '',
'content' => 'Текст тестовой страницы курса обучения на bezumkin.ru',
));
}
else {
return '';
}
}
Вот мы и немного оформили наши две страницы с помощью шаблонов Fenom и Twitter Bootstrap.
Заключение
На следующем уроке мы сильнее погрузимся в шаблонизацию и научимся работать с синтаксисом Fenom.
Попробуем вывести панель навигации по сайту, написать отдельный шаблон для страницы Test и выделить общие элементы двух шаблонов в отдельный файл, чтобы не копировать один код (head, footer).
На данный момент наш сайт выглядит вот так.
0
👍
👎
❤️
🔥
😮
😢
😀
😡
5 363
02.06.2015, 08:35:00
13 комментариев
Семён Лобачевский
02.06.2015, 13:59:29
Такой вопрос: по текущей логике, у нас при каждом обращении к главной странице сайта, запускается контроллер Controllers_Home, в котором есть функция run(), а в ней обращение к шаблонизатору Fenom. Так вот это обращение идёт каждый раз и пересоздаётся папка с кэшем? или при каком-то условии, подгружается из кэша?
Василий Наумкин
02.06.2015, 14:02:29
Нет, папка с кэшем только проверяется на существование, потому что без неё Fenom выбросит исключение и будет fatal error.
Fenom сам кэширует скомпилированные шаблоны, и сам загружает их из своего кэша - у нас об этом голова вообще не болит. Хоть метод для очистки кэша мы и задали, но пока нигде не используем.
Алексей
20.10.2015, 19:26:34
Интересно... Появилась ошибка на хостинге Nic.ru: Fatal error: Undefined constant 'T_ABSTRACT' in .../docs/Core/Fenom/Template.php on line 254 На другом хостинге и на локалке всё нормально. Вроде как это вопрос версии php, но перебрал все от 5.2 до 5.6. Расширения тоже перепроверил на всякий случай.
вздохнул... всё перепроверил, сделал заново - не помогло. Нет ли версий - что это может быть?
Василий Наумкин
20.10.2015, 22:35:13
Нужно проверить, всё ли в порядке с модулем PHP Tokenizer - именно к нему идёт обращение на 254 строке.
Алексей
21.10.2015, 00:47:04
Вот ведь... 2 раза включённые модули проверил. Модуль был выключен. Благодарю!
Василий Наумкин
21.10.2015, 06:16:57
На здоровье!
Николай Савин
03.01.2016, 13:41:07
Столкнулся с ошибкой. В классе Home.php упорно не желали вызываться методы из переданного класса Core.php, Так как я новичок, и особенности ООП для меня пока не особо известны - ошибку искал долго. На Github нашел подсказку Василия - Опечатка в названии метода в файле Controller.php Оказывается Василий в предыдущих уроках опечатался и написал _construct вместо __construct. Помню заметил, но подумал "Ему виднее". В итоге метод не срабатывал и экземпляр класса core дальше не передавался. С другой стороны подобный поиск ошибки заставил меня прогнать весь код в голове заново. Я потренировался писать свои методы, посмотрел, что срабатывает, а что нет. Так что получилась дополнительная практика.
Василий Наумкин
03.01.2016, 14:48:14
Ты бы дал ссылку на очепятку - я бы поправил.
Николай Савин
03.01.2016, 15:21:31
СсылкаПосле этой строки > Давайте создадим новую директорию /core/controllers/ и добавим в неё класс Home.php:
В классе метод __construct с очепяткой назван (не хватает _ )
Василий Наумкин
03.01.2016, 15:25:08
Спасибо, поправил!
Александр
29.01.2016, 15:22:28
Василий, не подскажешь где почитать доступно о такой форме записи
почему именно так, а не, условно,
как мы раньше вызывали методы своих классов? На php.net почитал, но ничего толком не понял. Спасибо.
Александр
29.01.2016, 15:45:50
Почитав stackoverflow.com и php.net подробнее, сформулировал ответ так: Такой записью мы вызываем статический элемент без создания экземпляра класса Пока только непонятно, почему метод registerAutoload создан именно статическим, но думаю ответ появится в процессе дальнейшего чтения документации по этой теме.
Василий Наумкин
29.01.2016, 16:01:52
Потому что для загрузки файлов не нужно инициализировать весь класс.
Статические методы - это, грубо говоря, обычные функции, которым не нужно обращаться к другим методам или свойствам самого класса. Вернее, обращаться они могут только к таким же статическим методам.
bezumkin.ru
Личный сайт Василия Наумкина
Прямой эфир
Василий Наумкин
03.12.2024, 13:13:34
Генерация - это создание статичный файлов, для их работы потом pm2 не нужен, только правильная настр...
Василий Наумкин
01.07.2024, 11:56:41
Да, верно, именно так.
А в контроллере, скорее всего, ловить данные методом post.
Василий Наумкин
26.06.2024, 09:38:15
О, точно, вылезает если не залогинен.
Спасибо, исправил!
Василий Наумкин
09.04.2024, 04:45:01
> Ошибка 500
Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи.
...
russel gal
09.03.2024, 20:17:18
> А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал...
Александр Наумов
27.01.2024, 03:06:18
Василий, спасибо!
Извини, тупанул.