Шаблонизатор php своими руками

Обновлено: 07.07.2024

Как такое можно реализовать? И Пожалуйста объясните, как работают шаблонизаторы, как сделать вывод новостей(из бд)?

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, установленного по умолчанию.

sourse

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

Многие 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-а, вам нужно пройти следующие шаги:

  1. Инициализировать авто-загрузчик Twig-а, для того чтобы классы шаблонизатора подгружались автоматически.
  2. Инициализировать загрузчик шаблонов. В нашем случае эт Twig_Loader_FileSystem. В качестве аргумента передаём путь к каталогу с шаблонами.
  3. Создать объект самого Twig и передать ему уже сконфигурированные настройки.
  4. Подгрузить нужный нам шаблон с помощью метода loadTemplate, передав в него название используемого шаблона. В качестве результата метод вернёт экземпляр шаблона.
  5. Сформировать массив вида "ключ-значение", где ключи - это названия переменных, а значения - данные, выводимые в шаблоне. Затем этот массив нужно передать в метод 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.

Что нам предстоит сделать:

  1. Подготовить шаблон (написать его в переменной, импортировать или достать из template-тега).
  2. Подготовить данные для шаблона.
  3. Поместить данные и шаблон в шаблонизатор.
  4. Поместить в DOM разметку, полученную из шаблонизатора.

Представим, как может выглядеть третий пункт:

На самом деле API шаблонизатора может выглядеть так, как вам нравится — всё зависит от задач.

Возможные способы реализации

Есть много способов реализовать шаблонизатора для DOM под капотом — от самых простых до сложнейших. Рассмотрим два основных:

  1. Заменить по регулярному выражению все переменные, встречающиеся в шаблоне, на данные и с помощью innerHTML поместить получившуюся разметку в DOM.
  2. Написать полноценный интерпретатор шаблонов, который будет символ за символом читать шаблон, разбивать его на токены, строить синтаксическое дерево и по этому дереву собирать разметку.

Сейчас мы осуществим первый способ реализации, чтобы обрести базовое понимание шаблонизации.

Реализуем шаблонизатор для DOM

Попробуем заставить работать следующий код:

Раз мы приняли решение делать шаблонизатор для DOM на классе, напишем заготовку такого класса:

Конструктор принимает шаблон в виде обычной строки, а его превращение в разметку будет скрыто в методе compile.

Proof of concept — регулярное выражение

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

Мы договорились о способе записи переменных в шаблоне — >. Найти такие фрагменты в строке нам поможет простое регулярное выражение /\\>/.

Попробуем применить регулярное выражение к строке с помощью метода exec:

Пробуем дальше — у нас в шаблоне наверняка может встретиться не одна переменная, а несколько.

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

  1. Нужно добавить ему флаг g , что значит global — искать все совпадения. Регулярное выражение с флагом g будет хранить и изменять своё состояние.
  2. Регулярное выражение надо применить к строке несколько раз. Сколько точно, заранее неизвестно. В этом случае отлично подходит цикл while, а условием для него будет служить знание того, что exec возвращает null, когда совпадение не найдено.

Посмотрим на примере:

Чтобы не писать exec вручную, завернём его в цикл. Но нам нужно не просто выполнить exec, а ещё и поработать с его результатом. Для этого воспользуемся особенностью JS, когда операция присваивания возвращает присваиваемое значение:

Теперь этот цикл пройдётся по всей строке и найдёт все совпадения — то что нужно!

Пишем метод compile

Теперь, когда у нас достаточно навыков работы с регулярным выражением, нужно его применить. Алгоритм следующий:

  1. находим совпадение в строке шаблона,
  2. очищаем от пробелов название переменной,
  3. заменяем в шаблоне все вхождения этой переменной на значение из контекста,
  4. повторяем.

Интересный момент в выражении 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 не позволяет вставлять один шаблон в другой.

Мне необходимо создавать переменную с шаблонам а потом как и обычно вставить её в шаблон и от рисовать, но я не могу понять как мне в переменную засунуть шаблон, ведь он сразу же выбрасывается на страницу!

Читайте также: