Шаблонизатор php своими руками
Как такое можно реализовать? И Пожалуйста объясните, как работают шаблонизаторы, как сделать вывод новостей(из бд)?
P.S: Отлично подходит шаблонизатор DLE. Smarty не предлагать, уж очень нагруженный шаблонизатор, чуть ли не отдельный язык уже.
простой шаблонизатор
Здравствуйте я хочу сделать шаблонизатор вот у меня есть маленький код .
Шаблонизатор
$page_content = include_template('main.php', ); $layout_content = include_template('layout.php', .
Для лентяев, код с Хабра
1) Смысл с использования ООП, если задать настройки ($cache_dir и $ext) можно только путем изменения кода класса?
2) Внутри класса необходимо указывать на то, куда относятся эти переменные (к классу через self::$. или к объекту через $this->. ) - в данном случае это два notice о несуществующих переменных.
3) Нет никакой проверки на имя файла. Несмотря на то, что это шаблонизатор, проверку выполнять все же надо, имхо.
4) Еще можно понять фигурные скобки вокруг единственной инструкции в условиях (а-ля "для дальнейшей расширяемости"), но никак не на одной строчке с инструкцией, да еще и без пробелов.
Способ вызова этого метода внутри метода load подразумевает использование модификаторов доступа, отличных от public, установленного по умолчанию.
Как правило, все шаблонизаторы похожи друг на друга и различаются только какими-то специфическими особенностями и деталями. Главная задача шаблонизаторов - разделить бизнес логику приложения и вывод данных на страницу, таким образом, позволив разработчикам и дизайнерам работать одновременно, не капая друг другу на мозги.
Многие PHP фрэймворки, включая: Zend Frameworkd, Agavi, CackPHP и CodeIgniter, по-своему реализуют разделение бизнес логики и вывод данных. Однако, если вы не любите фрэймворки или ваш проект слишком мал для их использования, то вы можете воспользоваться какой-то отдельной системой построения шаблонов. К счастью, нам есть из чего выбирать. Smartym Savant, Dwoo. этот список можно продолжать и продолжать, однако в этой статье я покажу вам, как работать с шаблонизатором Twig.
Установка
Существует множество способов установки Twig-a. Самый простой и быстрый - это скачивание компонента с GitHub, после чего архив необходимо распаковать, и перекинуть каталог lib в папку с нашим проектом.
Основы
Прежде чем приступить непосредственно к делу, давайте разберёмся с принципом работы шаблонизаторов. Обычное PHP приложение состоит из целого набора страниц, которые включают в себя как статический HTML код (меню, списки, изображения и т.д.), так и динамический контент (вывод данных из БД, xml файла, сервисы, …). С помощью Twig мы можем разделить данные процессы, создавая шаблоны со специальными маркерами, вместо которых в последствии будет вставляться динамический контент.
Значения для данных маркеров формируются в основном PHP скрипте; там же происходит общение с базой данных, xml парсинг и другие всевозможные операции. Таким образом, ваша страница будет строиться на основе 2х источников: шаблона с специальными вставками и PHP скриптов, где мы храним основной функционал. Это даёт возможность PHP разработчикам и дизайнерам одновременно работать над одними и теми же страницами.
Приступаем к делу
Для того чтобы посмотреть, как работает Twig, предлагаю рассмотреть простой пример:
Сохраните данный файл templates/thanks.tmpl. Обратите внимание на то, что все маркеры, представляющие собой переменные, помещены в двойные фигурные скобки. Подобная запись подскажет Twig-у, где и как осуществлять вставку данных.
Затем, нам необходимо создать основной скрипт, где будет происходить формирование переменных и данных:
В результате, если вы откроете данную страницу в браузере, то увидите следующее:
Для использования Twig-а, вам нужно пройти следующие шаги:
- Инициализировать авто-загрузчик Twig-а, для того чтобы классы шаблонизатора подгружались автоматически.
- Инициализировать загрузчик шаблонов. В нашем случае эт Twig_Loader_FileSystem. В качестве аргумента передаём путь к каталогу с шаблонами.
- Создать объект самого Twig и передать ему уже сконфигурированные настройки.
- Подгрузить нужный нам шаблон с помощью метода loadTemplate, передав в него название используемого шаблона. В качестве результата метод вернёт экземпляр шаблона.
- Сформировать массив вида "ключ-значение", где ключи - это названия переменных, а значения - данные, выводимые в шаблоне. Затем этот массив нужно передать в метод render(), который совместит шаблон с переданными данными и вернёт сгенерированный результат.
Условия
Twig также предоставляет нам возможность создавать условные выражения ‘if-else-endif’. Пример:
а вот и результат:
Также мы можем сделать многоуровневые проверки ‘if-elseif-else-endif’. Пример:
А вот и скрипт, где мы генерируем номер месяца и передаём его в шаблон:
Циклы
Twig также поддерживает цикл ‘for’. Он очень удобен, если нам необходимо пройтись по массиву. Пример:
В данном примере у нас простой не ассоциативный массив. На каждой итерации мы будем получать по одному элементу и выводить его в элементе списка. Вот и скрипт:
Для того чтобы пройтись по ассоциативному массиву, мы можем обращаться к ключам через “точку”. Пример:
Для того чтобы достучаться до значений массива в шаблоне, сначала пишем имя переменной, в которой хранится сам массив. Затем ставим точку и пишем название ключа, по которому достаём данные:
Такой же подход может быть применён для работы с объектами.
Дамп данных
Безусловно циклы вам пригодиться при выводе данных из БД. Пример:
В следующем фрагменте кода я использую PDO подключение к MySQL базе данных ‘world’. Если вы хотите попробовать данный пример, то вам нужно сформировать базу самим:
Тут стоит отметить несколько вещей:
Мы используем метод getchObject(), который вернёт нам строки из таблицы в виде объектов. Названия полей будут соответствовать названиям колонок. Затем эти объекты мы помещаем в массив и передаём его в шаблон. В шаблоне, используем цикл и выводим данные.
В данном примере также используется встроенный в Twig фильтр `escape`. По умолчанию данный фильтр пользуется функцией htmlspecialchars() для фильтровки данных. Это неплохая защита от XSS атак.
Подгрузка шаблонов
Также в Twig-е есть ещё одна команда - `include`, которая позволяет подключать содержание других шаблонов. Это может пригодиться, когда вы захотите прикрепить к вашим файлам меню, заголовок или подвал.
Для демонстрации представьте, что данный код - это главный шаблон:
Все секции данной страницы находятся в отдельных файлах и подключаются сюда с помощью команды `include`. Давайте посмотрим, как выглядят подключаемые файлы:
А вот и главный PHP скрипт:
Обратите внимание, что нам не нужно загружать все шаблоны функцией loadTemplate. Главное подключить основной шаблон. Каждый мелкий под-шаблон загрузится автоматом. Переменные и значения, переданные в главный шаблон, будут доступны во всех подключаемых шаблонах.
Фильтрация данных
В данной статье мы уже затронули тему фильтров. Давайте посмотрим, какие ещё возможности в данной сфере предоставляет нам Twig.
Давайте рассмотрим, к примеру, фильтр ‘date’. Данный фильтр даёт нам возможность формировать дату и время, используя нативные для PHP маркеры. Пример:
Также вы можете воспользоваться фильтрами `upper`, `lower`, `capitalize`, `title` для контроля заглавных и прописных букв:
Фильтр `striptags` уберёт из текста все HTML и XML элементы:
Фильтр `replace` позволяет быстро и просто заменять какие-то значения в строке на нужные нам. Пример:
Вы уже видели фильтр `escape` в действии. В Twig также есть фильтр, который делает абсолютно противоположное действие - `raw`. Его следует использовать только для html кода, который вы считаете 100% безопасным.
Если же вам нужно применить `escape` к большому блоку кода, то вы можете воспользоваться синтаксисом `autoescape`, передав булево значение true/false для активации и дезактивации фильтрации `escape`. Пример:
Теперь вы уже больше знаете о Twig-e и можете использовать условия, циклы и фильтры.
5 последних уроков рубрики "PHP"
Фильтрация данных с помощью zend-filter
Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.
Контекстное экранирование с помощью zend-escaper
Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.
Подключение Zend модулей к Expressive
Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.
Совет: отправка информации в Google Analytics через API
Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.
Прежде чем начинать изучать шаблонизацию, давайте вспомним два базовых подхода к созданию разметки.
Перед нами два отрывка кода, которые отвечают за одинаковую разметку для списка чатов: декларативный и императивный. Так это выглядит в HTML:
Теперь создаём такое же дерево, но через DOM API в JavaScript:
HTML выглядит понятнее, чем множество однотипных вызовов DOM API. Однако есть и минус: HTML статичен — его прописывают один раз и пользуются, а если нужно описать десятки или сотни однотипных элементов на странице, придётся написать всю разметку.
Есть огромный соблазн отдать эту рутинную работу коду. Или, например, когда десятки или сотни элементов приходят с сервера в процессе работы приложения, нужно создавать dom-элементы динамически, наполняя их данными, как в примере кода выше.
Где-то на стыке этих двух подходов работы с DOM появляется шаблонизация. С одной стороны, она позволяет описать разметку декларативно, а с другой стороны — описать динамические данные прямо в этой разметке.
Представьте, если бы вы могли создать DOM-дерево с динамическими данными, не используя createElement и описание свойств, а например, вот так:
Такая запись читается проще, чем манипуляции с document.createElement. Здесь можно:
- ясно увидеть, где должны быть имена классов и в каких местах они динамические;
- представить, как выглядит DOM-дерево сразу, не прикидывая в голове цепочку append (добавлений) элементов друг в друга;
- рендерить куски вёрстки быстро и наглядно.
К подобному синтаксису шаблона мы и будем стремиться.
Зачем это всё?
Действительно, зачем в век React, Angular и Vue заниматься такой мелочью, как шаблонизация? Все современные фреймворки умеют динамически подставлять данные в DOM и даже больше: циклы, условные операторы, компоненты, жизненный цикл.
В конце концов, если не пользоваться фреймворками — есть уже готовые шаблонизаторы, можно же взять их?
Сколько бы ни было на рынке инструментов, какие бы возможности они ни предоставляли, фактически всё сводится к 26 буквам английского алфавита, десятку символов и идеям: паттернам программирования и проектирования, принципам построения чистой архитектуры и чистого кода, шаблонам решения типовых задач.
Понимая идеи и принципы решения тех или иных задач, вам будет проще разобраться в любых существующих инструментах — вы будете понимать, какую задачу и с помощью каких принципов они решают. Такой подход намного продуктивнее, нежели простое заучивание API-фреймворков.
Именно поэтому написана эта статья — чтобы показать один из возможных подходов к динамическому формированию разметки.
Идея и синтаксис шаблона
Шаблонизатор — это функция, которая на вход получает некоторую разметку в виде чистого текста и контекст, а на выход даёт готовый DOM-элемент или текст, готовый к использованию в innerHTML. Под контекстом подразумевается набор информации, который подставляется вместо переменных в шаблонной строке.
Чтобы шаблонизатор мог работать, нужно придумать соглашение о синтаксисе — как описать в шаблоне места, куда должны подставляться данные из контекста. Обычно используют какие-нибудь скобки, в которые помещают идентификаторы переменных.
Скобки удваиваются, чтобы не спутать динамические данные со статическим текстом, который может быть в шаблоне. Они достаточно часто употребляются в текстах, поэтому без удвоения их легко перепутать:
Если выбрать круглые скобки в качестве маркера динамических данных и не удвоить их, непонятно, где переменная, а где просто текст в скобках.
Примем за обозначение переменных в шаблоне удвоенные фигурные скобки — такое решение достаточно распространённое. Таким образом шаблон для примера выше будет таким:
Хранение шаблона
Так как шаблон — это строка, то его можно хранить просто в строке 🙂
Значение у скрипта type отличается от text/javascript, поэтому браузер не будет пытаться обработать его как JavaScript.
Получить содержимое шаблона очень просто:
Также организовать хранение шаблона можно в файле с любым расширением и импортировать его. У популярных шаблонизаторов зафиксированы свои расширения, чтобы редакторы кода могли легко их распознавать.
Можно создать и использовать шаблоны следующим образом:
Однако для такого решения, возможно, придётся настроить ваш сборщик, чтобы он корректно импортировал подобные файлы.
Желаемый синтаксис использования
Теперь, когда мы понимаем синтаксис и метод хранения шаблона, пора подумать о том, как оживлять этот шаблон и превращать его в HTML.
Что нам предстоит сделать:
- Подготовить шаблон (написать его в переменной, импортировать или достать из template-тега).
- Подготовить данные для шаблона.
- Поместить данные и шаблон в шаблонизатор.
- Поместить в DOM разметку, полученную из шаблонизатора.
Представим, как может выглядеть третий пункт:
На самом деле API шаблонизатора может выглядеть так, как вам нравится — всё зависит от задач.
Возможные способы реализации
Есть много способов реализовать шаблонизатора для DOM под капотом — от самых простых до сложнейших. Рассмотрим два основных:
- Заменить по регулярному выражению все переменные, встречающиеся в шаблоне, на данные и с помощью innerHTML поместить получившуюся разметку в DOM.
- Написать полноценный интерпретатор шаблонов, который будет символ за символом читать шаблон, разбивать его на токены, строить синтаксическое дерево и по этому дереву собирать разметку.
Сейчас мы осуществим первый способ реализации, чтобы обрести базовое понимание шаблонизации.
Реализуем шаблонизатор для DOM
Попробуем заставить работать следующий код:
Раз мы приняли решение делать шаблонизатор для DOM на классе, напишем заготовку такого класса:
Конструктор принимает шаблон в виде обычной строки, а его превращение в разметку будет скрыто в методе compile.
Proof of concept — регулярное выражение
Прежде чем писать реальный код в заготовке класса, давайте потренируемся на тестовых данных. В первую очередь нам надо научиться находить в строке шаблонную переменную и на что-то её заменять.
Мы договорились о способе записи переменных в шаблоне — >. Найти такие фрагменты в строке нам поможет простое регулярное выражение /\\>/.
Попробуем применить регулярное выражение к строке с помощью метода exec:
Пробуем дальше — у нас в шаблоне наверняка может встретиться не одна переменная, а несколько.
Дело в том, что у регулярных выражений есть несколько хитростей. В нашем случае регулярное выражение находит первое совпадение и останавливает работу метода exec. Требуется два шага, чтобы заставить регулярное выражение работать со всеми совпадениями.
- Нужно добавить ему флаг g , что значит global — искать все совпадения. Регулярное выражение с флагом g будет хранить и изменять своё состояние.
- Регулярное выражение надо применить к строке несколько раз. Сколько точно, заранее неизвестно. В этом случае отлично подходит цикл while, а условием для него будет служить знание того, что exec возвращает null, когда совпадение не найдено.
Посмотрим на примере:
Чтобы не писать exec вручную, завернём его в цикл. Но нам нужно не просто выполнить exec, а ещё и поработать с его результатом. Для этого воспользуемся особенностью JS, когда операция присваивания возвращает присваиваемое значение:
Теперь этот цикл пройдётся по всей строке и найдёт все совпадения — то что нужно!
Пишем метод compile
Теперь, когда у нас достаточно навыков работы с регулярным выражением, нужно его применить. Алгоритм следующий:
- находим совпадение в строке шаблона,
- очищаем от пробелов название переменной,
- заменяем в шаблоне все вхождения этой переменной на значение из контекста,
- повторяем.
Интересный момент в выражении new RegExp(match[0], ‘gi’). Вы помните, что exec первым элементом массива возвращает полное совпадение из строки регулярному выражению. Здесь мы создаём из этого совпадения новое регулярное выражение, чтобы заменить все вхождения в шаблон подобной строки на настоящее значение.
Такая реализация кажется достаточной, но на самом деле нужно разобраться с парой моментов:
- Что делать, если в контексте не передано нужной переменной?
- Что делать, если в нужном ключе объекта лежит не примитив, а объект или массив?
- Что делать, если в нужном ключе объекта лежит функция?
Эти вопросы не имеют однозначного ответа и выходят за рамки статьи: у нас нет цели написать полноценный шаблонизатор — мы хотим познакомиться с принципами его построения. Однако остановимся на последнем вопросе, чтобы в будущем не наделать ошибок.
Итак, если в ключе контекста встречается функция, нужно корректно её обработать. Прежде всего нужно договориться о правиле применения функций в шаблоне, на соблюдение которого мы будем полагаться.
Пусть в шаблоне переменные значения с функциями помещаются только в атрибуты on*:
Обратите внимание: в HTML это именно вызов функции со скобками в конце.
Такой способ можно довольно просто добавить в текущий шаблонизатор, чтобы не перегружать его ненужной логикой. Всё остальное будет лишним и слишком сложным в ситуации простого знакомства с шаблонизацией. А ещё этот механизм не позволяет передавать в функцию атрибут event. Минусов хватает, но начинать с чего-то надо 🙂
Чтобы добавить такие обработчики, нужно проверить в методе компиляции, что значение из контекста по ключу является функцией. Если это так, то требуется подставлять не просто значение, но и добавлять в конец вызов функции. Например, мы передали в контексте <>> для шаблона , а на выходе должны получить:
Но откуда возьмётся handleClick в области видимости, где его будет вызывать Browser API? Чтобы этот HTML-элемент работал корректно, функция handleClick должна находиться в window — именно там её будет искать браузер.
Помимо добавления скобок, ещё придётся присвоить функцию из контекста в какое-то поле window. Сделаем это:
Заключение
Итак, мы изучили, что такое шаблонизация, какие вопросы стоит задавать при создании шаблонизатора и как на них можно отвечать. Реализация получилась, что называется, на коленке, но она вполне отражает ход размышлений и при этом даже работает 🙂
Несомненно, эту реализацию можно улучшить, но стоит ли? В приведённом случае мы всё равно подвержены уязвимости в виде innerHTML, потому что не создаём в шаблонизаторе настоящий DOM, а только оперируем строкой.
Немного практики
Сделайте так, чтобы в синтаксисе шаблона можно было размещать обращения к полям объекта:
Задача шаблонизатора - только подставлять определённые значения в определённые места, а все циклы я могу написать и на PHP, и промежуточный язык для этого не требуется.
Итак, привожу код своего шаблонизатора, которым я настоятельно рекомендую Вам пользоваться:
private $dir_tmpl ; // Директория с tpl-файлами
private $data = array (); // Данные для вывода
public function __construct ( $dir_tmpl ) $this -> dir_tmpl = $dir_tmpl ;
>
/* Метод для добавления новых значений в данные для вывода */
public function set ( $name , $value ) $this -> data [ $name ] = $value ;
>
/* Метод для удаления значений из данных для вывода */
public function delete ( $name ) unset ( $this -> data [ $name ]);
>
/* При обращении, например, к $this->title будет выводиться $this->data["title"] */
public function __get ( $name ) if (isset( $this -> data [ $name ])) return $this -> data [ $name ];
return "" ;
>
/* Вывод tpl-файла, в который подставляются все данные для вывода */
public function display ( $template ) $template = $this -> dir_tmpl . $template . ".tpl" ;
ob_start ();
include ( $template );
echo ob_get_clean ();
>
>
?>
Всего 1 файл размером 0.5 КБ. Но при этом всё самое важное данный класс сделает.
Теперь создадим tpl-файл (пусть называется menu.tpl), который будет без проблем обработан этим шаблонизатором:
И, наконец, давайте напишем PHP-файл, который будет вызывать шаблонизатор:
Здравствуйте, пишу свой шаблонизатор php, в данный момент выглядит он вот так:
В данный момент суть такова:
Cоздаю новый шаблон: $template = new Template($root_dir."template/manager/");
Я создаю массив с переменными:
Шаблон выглядит так
и вывожу на страницу
Данный Class не позволяет вставлять один шаблон в другой.
Мне необходимо создавать переменную с шаблонам а потом как и обычно вставить её в шаблон и от рисовать, но я не могу понять как мне в переменную засунуть шаблон, ведь он сразу же выбрасывается на страницу!
Читайте также: