PHP-класс для построения шаблонов

в 10:57, , рубрики: Песочница, метки: , , , ,

Всем привет. Хочу представить очередной велосипед написанный на PHP с использованием Document Object Model. В чем его отличие от остальных трёхколёсных представителей того же вида? На самом деле отличий не так уж и много, он сочетает в себе лучшее из многих. Например:

1. Полное разделение html и php.
2. Никаких дополнительных меток в шаблонах типа

<!-- BEGIN:block --> <!-- END:block -->

3. Возможность встраивать в верстку содержимое других файлов шаблона, как из php, так и используя специальный тэг в верстке.
4. Возможность создавать любой html-тэг на лету.
5. Возможность сохранение в html файл все что было сгенерировано и собрано.
6. Проверка существования html-файла запрашиваемой страницы перед тем как генерировать шаблон.

Чтобы всем сразу стало понятно на сколько он удобен и прост в обращении, я расскажу и покажу как я его использовал для создания одного из своих проектов (подозреваю что перепишу все свои проекты под него).

Первое что я обычно делаю это получаю всю информацию из БД о странице (ключевые слова, описание страницы, название шаблона и адреса css и js файлов). Все это я сохраняю в массив $head. Дальше я получаю из БД контент и сохраняю в массив $page. И приступаю к работе с классом.

Итак, сначала я вызываю конструктор класса и передаю в него все необходимые параметры:

$tpl = new Template;
$tpl -> ext = TPL_EXTENSION; # расширение файлов в каталоге шаблона
$tpl -> htm = CACHE_EXTENSION; # расширение для уже сгенерированных страниц
$tpl -> skin_dir = DIR_TEMPLATES; # директория, в которой лежат все шаблоны сайта (например templates)
$tpl -> js_dir = DIR_JS; # директория где нужно искать JS файлы
$tpl -> css_dir = DIR_CSS; # директория где лежат CSS
$tpl -> img_dir = DIR_IMG; # директория где картинки
$tpl -> skin = $_SESSION['skin']; # имя шаблона, который я хочу использовать
$tpl -> cache = DIR_CACHE; # куда сохранять готовые html
$tpl -> log = FILE_T_LOGS; # куда писать логи
$tpl -> tag_start = SYMBOL_START_TAG; # Символ, с которого начинаются переменные в шаблоне
$tpl -> tag_end = SYMBOL_END_TAG; # Символ, которым заканчиваются переменные в шаблоне
$tpl -> dir_delimeter = DIRECTORY_SEPARATOR;
$tpl -> space = SYMBOL_SPACE; # символ, заменяющий пробел.

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

if($tpl -> TestPageStatus() === TRUE)
   {
     require $tpl -> cacheFileName;
   }
else
  {
     $tpl -> page('index'); # передаем имя файла шаблона, кстати их можно передать несколько, через запятую
     $tpl -> assign('HEAD',$head);
     $tpl -> assign('CONTENT',$page);
     $tpl -> build(); # даем команду собрать шаблон
     $tpl -> ShowPage(); # выводим.
   }

Вот собственно и все методы, которые нужно использовать для того чтобы вывести страницу.

Теперь разберем еще пару-тройку полезных методов этого класса. Допустим что мы уже передали в класс все необходимое, но еще не дали ему команду на вывод, потому-что вдруг вспомнили что нам нужно создать несколько Html-тэгов в шаблоне. Это тоже делается очень просто. Для начала нужно найти блок, в котором мы хотим что-то добавить. Найти можно 2 способами:

$tpl -> findById('findMe');
$tpl -> findByTagName('div');

Метод findById логично подразумевает что в шаблоне все id тэгов уникальны. А метод findByTagName вернет первый подходящий.
Результат который мы получили поиском мы должны передать в метод $tpl -> createChild(), чтобы иметь возможность создавать в найденном элементе, дочерние тэги. Метод createChild кстати, после создания нового элемента, возвращает его нам, так что мы можем использовать только что созданный элемент еще где-нибудь.

Ковыряясь и экспериментируя я нашел 3 способа создания тэгов в шаблоне, поэтому покажу сразу 3 примера. Пример1:

Нам нужно создать

<div id="child" class="test"></div>

внутри

<div id="parent"></div>
  $parent = $tpl -> findById('parent');
  $tpl -> createChild($parent,'div', 'id=child, class=test');

Получим:

<div id="parent">
   <div id="child" class="test"></div>
</div>

Пример 2:

Нам нужно создать

<div id="child" class="test">Какой-то текст</div> 

внутри

<div id="parent"></div>
  $parent = $tpl -> findById('parent');
  $tpl -> createChild($parent,'div', 'id=child,class=test', 'Какой-то текст');

Получим:

<div id="parent">
   <div id="child" class="test">Какой-то текст</div>
</div>

Пример3:
Нам нужно создать

<div>Новый элемент</div>

в первом попавшемся span-элементе

  $parent = $tpl -> findByTagName('span'); # (1)
  $tpl -> createChild($parent, 'div', 'Новый элемент'); # (2)

(1) Поиск родителя не по id, а по тэгу найдет первого подходящего
(2) Если нам не нужны атрибуты, а только значение нового элемента, то их можно не передавать

Получим:

<span>
    <div>Новый элемент</div>
  </span>

И после этих манипуляций я уже вызываю ShowPage. И тут мы плавно подошли к еще 2 интересным моментам.
Представим ситуацию, что у нас есть шаблон, предположим что это шаблон list.tpl со списком, допустим, мобильных телефонов:

<div id="{CONTENT.Id}" class="shortInfo">
<p class="brand">{CONTENT.Brand}</p>
<p class="model">{CONTENT.Model}</p>
{CONTENT.Info}
</div>

Если мы передали информацию только по 1 телефону, то будет просто произведена замена переменных на их значения, а если мы передали информацию сразу по нескольким телефонам, то класс скопирует этот участок столько раз, сколько вариантов значений к нему пришло. И это он сделает сам, в отличие, например от класса xTemplate, которому приходилось под каждое значение вызывает assign и parse
Правда есть один не очень удобный момент, если после этого блока стоят какие-то еще, например:

<div id="{CONTENT.Id}" class="shortInfo">
<p class="brand">{CONTENT.Brand}</p>
<p class="model">{CONTENT.Model}</p>
{CONTENT.Info}
</div>
<div>Еще какой-то блок</div>

То в такой ситуации нам придется применить небольшую хитрость, упаковав наш мобильник

<div>   
   <div id="{CONTENT.Id}" class="shortInfo">
      <p class="brand">{CONTENT.Brand}</p> 
      <p class="model">{CONTENT.Model}</p>
      {CONTENT.Info}
   </div>
</div>
<div>Еще какой-то блок</div>

В таком случае все мобильники будут появляться друг за другом, внутри

<div></div>

, а «Еще какой-то блок» так и останется внизу.

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

Представьте что верстальщик хочет чтобы содержимое page.html файла было добавлено в блок файла list.html, для этого он в нужном месте файла list.html дописывает

<filename>page</filename>

и когда класс увидит этот тэг он заменит его на содержимое файла page.html

Количество таких вставок не ограничено и их расположение абсолютно не критично, поэтому можно вставлять их как угодно и в любом количестве.

Вот пожалуй и все, если что-то вспомню, сообщу дополнительно. Спасибо что дочитали до конца.

  1. ER:

    Я так понимаю, речь идет о Smarty? Просто нигде не указано название

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js