Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Экзамен / web / example1 / Введение в PHP.doc
Скачиваний:
101
Добавлен:
18.05.2015
Размер:
3 Mб
Скачать

Отделение клиентская части программы от серверной части и шаблоны

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

1. PHP начинается со вставок скрипта в HTML-страницы. Например:

<?php include_once ("site.lib"); ?>

<html>

<head>

<title>

<?php print_header (); ?>

</title>

</head>

<body>

<h1>

<?php print_header (); ?>

</h1>

<table border="0" cellpadding="0" cellspacing="0">

<tr>

<td width="25%">

<?php print_links (); ?>

</td>

<td>

<?php print_body (); ?>

</td>

</tr>

</table>

</body>

</html>

<?php //site.lib - код PHP программы

$dbh = mysql_connect ("localhost", "sh", "pass")

or die (sprintf ("Не могу открыть соединение с MySQL [%s]: %s",

mysql_errno (), mysql_error ()));

@mysql_select_db ("MainSite")

or die (sprintf ("Не могу выбрать базу данных [%s]: %s",

mysql_errno (), mysql_error ()));

$sth = @mysql_query ("SELECT * FROM site", $dbh)

or die (sprintf ("Не могу выполнить запрос [%s]: %s",

mysql_errno (), mysql_error ()));

$site_info = mysql_fetch_object ($sth);

function print_header ()

{

global $site_info;

print $site_info->header;

}

function print_body ()

{

global $site_info;

print nl2br ($site_info->body);

}

function print_links ()

{

global $site_info;

$links = explode ("\n", $site_info->links);

$names = explode ("\n", $site_info->link_names);

for ($i = 0; $i < count ($links); $i++)

{

print "\t\t\t

<a href=\"$links[$i]\">$names[>$i]</a>

\n<br>\n";

}

}

?>

Преимущество этой концепции - возможность изменения дизайна без модификации самого кода программы. Как вариант данного подхода можно рассмотреть использование шаблонов для разделения PHP и HTML кода -. Чаще всего под шаблоном понимается некий документ ( в формате HTML или PHP), содержащий специальные метки, которые в процессе генерации страницы заменяются на информационные данные.

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

<html>

<head>

<title>%%PAGE_TITLE%%</title>

</head>

<body %%BODY_PROPERTIES%%>

<h1>%%PAGE_TITLE%%</h1>

<table border="0" cellpadding="0" cellspacing="0">

<tr>

<td width="25%">%%PAGE_LINKS%%</td>

<td>%%PAGE_CONTENT%%</td>

</tr>

</table>

</body>

</html>

Программа на PHP просматривает затем код шаблона и заменяет тэги вида %%:%% нужной информацией.

2. Логичным развитием предыдущего подхода является полный переход на php в том смысле, что в начале файла стоит открывающий тег "<?php", и дальше php-код не прерывается. Весь вывод делается через echo (print). Пример: страница подписки на новые ссылки в каталоге.

<?php

include "db-connect.inc";

include "login-check.inc";

if (!$logged_in) {

header ("Location: /register.php");

exit();

}

include "page-header.inc";

print("<h2 class="club_article_small_caption">Новости для клиентов

<table cellpadding=\"4\" cellspacing=\"0\" border=\"0\">");

$result = mysql_query("SELECT id, title, announce, news_date FROM news ORDER BY

news_date DESC LIMIT 10");

if (mysql_error())

print(mysql_error());

else

while ($row = mysql_fetch_assoc($result))

print("<tr><td>{$row[news_date]}");

if ($row["news_date"] > date("Y-m-d", time() - 3600*24*14))

print("<font color=\"#cc0000\">new!</font>");

print("</td><td>

<a href=\"read.php ? id={$row[id]}\"> <b>{$row[title]}</b></a>

<br>{$row[announce]}</td></tr>");

print("</table>");

include "page-footer.inc";

?>

Отметим, что этот код сложно читать, даже если добавить комментарии.

При использовании PHP можно попытаться использовать "шаблонизаторы" на основе функции eval($str). Эта функция расценивает текст, заданный в строке $str, как код PHP и исполняет его. Например:

$text = 'Здравствуйте, $name $fam!';

$name = "Пиня";

$fam = "Копман";

eval('echo "' . $text . '";');

Этот пример работы с мини-шаблоном выведет "Здравствуйте, Пиня Копмае".

Преимущество данного типа инструментов работы с шаблонами связано с тем, что от разработчика заранее не требуется определять текст или другую информацию для меток в шаблоне (таковыми метками служат слова $name и $fam). Также такие "шаблонизаторы" значительно выигрывают по скорости.

Рассмотрим пример создания домашней страницы SimplePage с помощью использования объектно – ориентированного программирования в PHP при котором дизайн сайта помещен прямо в исходный код.

Вверху страницы большая надпись “Домашняя страница SimplePage “. Далее следует меню: Главная страница, Биография, Ссылки.

По середине страницы идет текст раздела.

Внизу для удобства дублируется меню.

Сайт будет состоять из четырех основных файлов:

index.php – Главная страница

bio.php – Страница с биографией SimplePage

links.php – Страница с ссылками

html.php – Вспомогательный файл

В вспомогательном файле будем хранить все классы.

Определим абстрактный класс HTML-страницы в файле html.php:

abstract class HTMLPage

{

protected $Title = ;

function __construct($Title)

{

$this->Title = [Домашняя страница SimplePage ] . $Title;

}

function BeginHTML()

{

echo <<<HTML

<html>

<head>

<title>{$this->Title}</title>

</head>

<body>

HTML; }

function EndHTML()

{

echo <<<HTML

</body>

</html>

HTML; }

function Logo()

{

echo <h1>Домашняя страница SimplePage </h1>;

}

function Menu()

{

echo <<<HTML

<table>

<tr>

<td><a href=index.php>Главная страница</a></td>

<td><a href=bio.php>Биография</a></td>

<td><a href=links.php>Ссылки</a></td>

</tr>

</table>

HTML; }

abstract function MainText();

function Write()

{

$this->BeginHTML();

$this->Logo();

$this->Menu();

$this->MainText();

$this->Menu();

$this->EndHTML();

}

}

?>

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

function __construct($Title) – Создание и инициализация объекта (в нашем случае установка название страницы).

function BeginHTML() – Вывод заголовок html-файла.

function EndHTML() – Вывод окончания html-файла.

function Logo() – Вывод логотипа сайта.

function Menu() – Вывод главного меню сайта.

abstract function MainText() – Вывод основного содержания веб-страницы.

function Write() – Вывод веб-страницы, использую методы для вывода отдельных элементов веб-страницы.

Часть методов служит для вывода отдельных элементов страницы, таких, как меню, логотип и так далее. В методе Write все эти функции вызываются для того, чтобы вывести всю страницу целиком. Особое внимание следует уделить абстрактному методу MainText. Этот метод назвается абстрактным поскольку он не реализован в этом классе, а только объявлен. Этот метод будет переопределен и реализован в дочерних классах. Так на странице ссылок в этом методе будут выводиться ссылки, а на странице биографии - текст биографии SimplePage. Сам класс объявлен таже абстрактным, соответственно, будет невозможно создать экземляры такого класса.

В классе объявлена переменная $Title с областью видимости protected, то есть доступ к ней может получить либо сам класс либо его наследники.

Теперь осталось создать остальные три файла.

<?php // index.php

include_once(html.php);

class IndexPage extends HTMLPage

{

function MainText()

{

echo <p>Добро пожаловать на домашнюю страничку SimplePage;

}

}

$Page = new IndexPage(Главная страница);

$Page->Write();

?>

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

Преимущества использования ООП будут тем больше, чем больше будет сайт. Например, может потребоваться добавить новую страницу. Для этого надо будет лишь создать новый файл с классом производным от HTMLPage, переопределить метод MainText и создать соответствующий пункт меню. Также просто будет изменить дизайн всех страниц - все изменения будут происходить в классе HTMLPage, другие страницы унаследут дизайн автоматически.

3. Использование готовых классов шаблонов из библиотек

Примером одного из первых шаблонов PHP является FastTemplate.

-- main.tpl --

<html>

<head><title>{TITLE}</title>

</head>

<body>

{MAIN}

</body>

</html>

-- table.tpl --

<table>

{ROWS}

</table>

-- row.tpl --

<tr>

<td>{NUMBER}</td>

<td>{BIG_NUMBER}</td>

</tr>

</tr>

</table>

</body>

</html>

FastTemplate - представляет набор классов, позволяющих реализовать работу с шаблонами. Логику добавить в шаблон FastTemplate нельзя, вся она должна находиться в коде программы. Это обычный html-файл, в котором могут встречаться переменные особого вида, впоследствии обрабатываемые методами класса FastTemplate.

FastTemplate устарел, так как относится еще к третьей версии PHP.

Шаблон Smarty

Smarty - один из действующих проектов PHP, его официальный сайт - smarty.php.net. С этого сайта можно скачать набор классов Smarty для обработки шаблонов. Smarty не отделяет полностью логику от содержания. Поэтому в шаблоне Smarty могут быть условные операторы, операторы вставки файлов, операторы изменения переменных, циклы и т.п. Другая особенность Smarty - это компиляция шаблонов. Шаблоны переводятся в php-код, и интерпретатор PHP производит все необходимые действия. Для ускорения работы скомпилированные шаблоны кэшируются.

Начало - это установка Smarty. Smarty состоит из целого набора различных файлов-библиотек, которые нужно сделать доступными. Находятся они в каталоге /libs/ дистрибутива Smarty. Файл, в котором содержится определение самого класса Smarty, называется Smarty.class.php. Чтобы проверить, доступны ли библиотеки класса Smarty, нужно написать такой скрипт:

<?

// подключаем файл с описанием класса Smarty

require('Smarty.class.php');

// создаем экземпляр класса Smarty

$smarty = new Smarty;

?>

Если при его исполнении появилась ошибка, то нужно попробовать указать полный путь до файла описания класса. Кроме этого можно добавить директорию, где содержатся библиотеки, в include_path (в этом случае код менять не нужно). Установить константу SMARTY_DIR.

<?

define("SMARTY_DIR",

"c:/users/my/Smarty/libs/");

require(SMARTY_DIR."Smarty.class.php");

$smarty = new Smarty;

?>

Если библиотеки найдены, нужно создать директории, необходимые для работы Smarty:

templates – директория для хранения созданных шаблонов;

templates_c - директория, где Smarty будет хранить скомпилированные шаблоны;

configs - директория для хранения конфигурационных файлов;

cache - директория для кэша.

Эти имена задаются свойствами $template_dir, $compile_dir, $config_dir, $cache_dir класса Smarty, поэтому их можно переопределить. Рекомендуется использовать различные наборы директорий для каждого приложения, работающего с шаблонами Smarty.

Создадим перечисленные Smarty директории по адресу c:/smarty_dirs/book/. Заметим, что прочитать отсюда данные через браузер нельзя. Пусть наша программа (или приложение) находится по адресу /~my/tasks/book/. Для директорий $compile_dir и $cache_dir Smarty потребуется доступ на запись, так что нужно установить соответствующие им права для сетевого пользователя, с которым сервер работает по умолчанию (обычно это www или nobody).

Чтобы протестировать сделанные настройки, создадим простой шаблон и программу, обрабатывающую его с использованием механизма Smarty.

index.tpl (является Smarty шаблоном и находится в директории шаблонов c:/smarty_dirs/book/templates/)

{* Шаблон Smarty *}

Привет, {$name}!

index.php (является кодом нашей программы и находится в директории /~my/tasks/book/ или, что то же самое, в директории c:/users/my/tasks/book/)

index.php

В результате должны получить:

Привет, Вася!

Синтаксис шаблонов

Smarty определяет целый язык построения шаблонов. Это набор специальных конструкций (переменных, вызовов функций и методов и т.п) и html-тегов. Все элементы (теги) языка шаблонов Smarty заключаются между символами-ограничителями. По умолчанию это символы фигурных скобок "{" и "}", но их можно изменить. Все, что не заключено в такие ограничители, Smarty рассматривает как константы, не требующие обработки. В шаблоне index.tpl, приведенном выше, {$name} - это переменная, а строки "Привет," и "!" - не изменяющиеся в процессе обработки шаблона константы.

Комментарии в Smarty записываются между двумя звездочками:

{* Это комментарий. После обработки шаблона на экране не отображается *}

Каждый Smarty тег либо выводит значение переменной, либо вызывает какую-либо функцию. Функция записывается следующим образом:

{имя_функции атрибут1="значение1" атрибут2="значение2"}

Переменные в шаблоне могут быть нескольких типов:

Переменные, значение которым присваивается в php-скрипте пользователя, должны иметь перед именем знак доллара.

Например: {$first_name}

Элементы массива, значения которых были присвоены в php-скрипте пользователя, доступны в шаблоне с помощью синтаксиса {$имя_массива.ассоциативный_ключ}.

Например: {$person.last_name}

Элементы не ассоциативного массива доступны с помощью синтаксиса квадратных скобок: {имя_массива[числовой_индекс]}

Например: {$person[2]}

Свойства объектов, заданные в php-скрипте, доступны в шаблоне с помощью такого синтаксиса: {имя_объекта->имя_свойства}

Например: {$person->email}

Переменные, загруженные из конфигурационных файлов, заключаются между символами #. Также они доступны как элементы ассоциативного массива $smarty.config.

Например: {#bodyBgColor#} или {$smarty.config.bodyBgColor}

Кроме того, существует переменная {$smarty}, зарезервированная для некоторых специальных переменных шаблона, таких как переменные HTTP запроса, даты и времени.

В шаблонах Smarty определен ряд модификаторов, которые можно применять к переменным, пользовательским функциям или строкам с тем, чтобы модифицировать их значения. Чтобы применить модификатор, нужно указать его название после вертикальной черты, следующей за именем переменной, функции или строкой, к которой он применяется. Например, чтобы перевести значение переменной {$title} в верхний регистр, нужно применить к ней модификатор upper, т.е. написать следующее: {$title|upper}

Например, {$title|upper|truncate} переведет значение переменной в верхний регистр и урежет до 80 символов.

Конфигурационные файлы

Конфигурационные файлы используются для того, чтобы управлять глобальными переменными, используемыми в шаблоне, с помощью одного файла. Их идея очень похожа на таблицы стилей css. Конфигурационный файл содержит набор переменных и их значения. Перед именем переменной не ставится никаких дополнительных символов типа знака доллара. Значение переменной по желанию заключают в кавычки (двойные или одинарные), если оно состоит из нескольких строк, то его заключают в тройные кавычки.

# глобальные переменные

pageTitle = "List of documents"

bodyBgColor = #000000

tableBgColor = #000000

rowBgColor = #00ff00

[Customer]

pageTitle = "Список статей"

Intro = """Это значение состоит из

нескольких строк. Поэтому его нужно

заключить в тройные кавычки."""

# скрытая секция

[.Database]

host=localhost

db=book

user=nina

pass=123

Конфигурационный файл может состоять из нескольких разделов (секций), каждая из которых имеет имя и может загружаться отдельно от остальных секций. Имя секции заключается в квадратные скобки. Кроме секций в конфигурационном файле могут содержаться глобальные переменные - они не входят ни в одну секцию и всегда загружаются при загрузке конфигурационного файла. Если загружается какая-то одна секция, то загружаются ее переменные и глобальные переменные. Если переменная существует и как глобальная переменная, и как переменная секции, то используется переменная секции. Если вы одинаково назовете две переменные внутри одной секции, то будет использоваться последняя из них. В приведенном выше примере две секции - Customer и Database, а кроме них заданы глобальные переменные pageTitle, bodyBgColor, tableBgColor и rowBgColor.

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

Комментарии в конфигурационном файле можно обозначать символом #.

Загрузка конфигурационных файлов производится с помощью встроенной функции или метода config_load.

Методы

Для работы с шаблонами класс Smarty определяет набор методов.

void assign (смешанное значение);

void assign (имя переменной, смешанное значение);

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

<?php

// передаем пары имя/значение для

// переменной Name и

// Address в отдельности

$smarty->assign("Name","Вася");

$smarty->assign("Address",$addr);

// здесь $addr может быть и массивом

// передаем ассоциативный массив

$smarty->assign(array(

"city" => "Новосибирск",

"street" => "Пирогова"));

// таким образом, переменные city и street

// получат соответствующие значения

?>

Метод void append (смешанное значение);

void append (имя переменной, смешанное значение);

void append (имя переменной, смешанное значение, слияние);

Принцип действия этого примерно такой же, как и у assign. Метод append позволяет присоединить элемент к массиву. Если вы присоединяете значение к строковой переменной, то она преобразуется в массив, и значение добавляется уже в него. Так же, как и в assign, здесь можно передавать пары ключ/значение или ассоциативные массивы, содержащие эти пары. Если указать третий аргумент слияние равным TRUE, то значение будет не присоединено в качестве еще одного элемента, а слито воедино с текущим массивом.

$smarty->append(array(title => $title, author => $author))

Здесь если title была строкой, то она становится массивом и к нему добавляется еще один элемент со значением $title. То же самое происходит с переменной author.

Метод void config_load(имя файла, [имя секции]);

Метод загружает конфигурационный файл и встраивает его в шаблон. Аналогично этому методу действует функция config_load.

Пример: $smarty->config_load("task.conf","Database");

Метод void display(шаблон);

Метод отображает шаблон. У этого метода есть еще два опциональных параметра, о которых можно прочитать в документации.

Метод string fetch(шаблон);

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

Встроенные функции

Smarty поставляется с набором встроенных функций, интегрированных в язык шаблонов. Опишем некоторые из таких функций.Функция config_load имеет синтаксис:

{config_load file="имя_файла" }

Эта функция используется для загрузки в шаблон переменных из конфигурационных файлов. Кроме имени загружаемого файла, у этой функции может быть еще несколько дополнительных параметров. Например, параметр section, в котором указывают имя секции для загрузки. Пример:

{config_load file="task.conf"}

Функция capture имеет синтаксис:

{capture name="имя_блока"

assign="имя_переменной"} ...

{/capture}

Эта функция предназначена для того, чтобы собирать в переменную выходные данные шаблона вместо того, чтобы выводить их на экран. Все, что находится между {capture name="varname"} и {/capture}, будет записано в переменную с именем varname. Захваченный таким образом контент может быть использован в шаблоне посредством специальной переменной $smarty.capture.varname, где varname - значение, переданное в атрибут name функции capture. Если имя переменной не задано, будет использовано имя default.

Второй параметр assign задает имя переменной, которой будет присвоено захваченное выходное значение. Этот параметр, как и name, не обязательный.

Функция section

{section name="имя_секции"

loop="переменная_для_выч-ния_числа_итераций"

[,start="индекс_начальной_позиции"]

[, step="шаг"] [,max="максимум_итераций"]

[,show="показывать_ли_секцию"] }...

{/section}

Секция Section - это цикл для обхода элементов массива. Обязательными являются параметры name, с помощью которого задается имя секции, и loop, который представляет собой переменную, определяющую число итераций цикла. Как правило, loop - это переменная типа массив, и число итераций секции равно числу элементов этого массива. Чтобы вывести переменную внутри цикла, нужно после имени переменной указать в квадратных скобках имя секции.

{section name=art loop=$title}

Название: {$title[art]}<br>

{/section}

Пример. Цикл для обхода элементов массива. Функция foreach имеет синтаксис:

{foreach from="имя_массива"

item="имя_текущего_элемента"}

... {/foreach}

Кроме того, можно использовать дополнительные атрибуты key - имя ключа для текущего элемента массива и name - имя цикла, с помощью которого можно будет получать доступ к его свойствам. Атрибуты from и item - обязательные.

Циклы foreach являются альтернативой циклам section. Действие функции foreach очень похоже на работу цикла foreach в языке PHP.

{foreach from=$articles item=art}

Title: {$art}<br>

{/foreach}

Пример . Цикл foreach

Циклы foreach имеют свои собственные свойства. Получить доступ к ним можно таким образом: {$smarty.foreach.foreachname.varname}, где foreachname - это имя цикла, заданное его параметром name, а varname - имя свойства.

Оператор if, elseif, else

Синтаксис:

{if выражение} блок_действий

Действие оператора практически аналогично оператору if...elseif...else языка PHP. В выражениях могут использоваться следующие операторы сравнения: eq, ne, neq, gt, lt, lte, le, gte, ge, is even, is odd, is not even, is not odd, not, mod, div by, even by, odd by, ==, !=, >, <, <=, >=. Каждый из них обязательно должен быть отделен от окружающих его значений пробелами. В выражениях можно использовать круглые скобки и вызывать php-функции.

{if $name eq "Вася"}

Добро пожаловать, Вася.

{elseif $name eq "Петя"}

Добро пожаловать, Петя.

{else}

Добро пожаловать. А вы кто?

{/if}

Пример. Операторы if, elseif, else

{* этот пример не будет работать,

поскольку не поставлены

пробелы вокруг операторов сравнения *}

{if $name=="Вася" || $name=="Петя"}

...

{/if}

Решение задачи с помощью шаблонов Smarty

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

{* Smarty template index.tpl *}

{config_load file="task.conf" }

<html>

<head><title>{#pageTitle#}</title>

</head>

<body>

<ol>

{section name=art loop=$title}

<li><a href="{$fulltext[art]}">

{$title[art]}</a>

({$author[art]})

<br> <p> {$abstract[art]}

{/section}

</ol>

</body>

</html>

В файле конфигурации task.conf будем хранить название страницы и параметры для доступа к базе данных:

# глобальные переменные

pageTitle = "List of documents"

[Customer]

pageTitle = "Список статей"

[Database]

host=localhost

db=book

user=nina

pass=123

Скрипт (index.php), обрабатывающий написанный нами шаблон, может выглядеть таким образом:

Smarty;

$smarty->template_dir = "c:/smarty_dirs/book/templates/";

$smarty->compile_dir = "c:/smarty_dirs/book/templates_c/";

$smarty->config_dir = "c:/smarty_dirs/book/configs/";

$smarty->cache_dir = "c:/smarty_dirs/book/cache/";

// вышеприведенный блок лучше вынести в отдельный файл

$smarty->config_load("task.conf","Database");

$host = $smarty->get_config_vars("host");

$user = $smarty->get_config_vars("user");

$pass = $smarty->get_config_vars("pass");

$db = $smarty->get_config_vars("db");

$conn = mysql_connect($host, $user, $pass) or die("Cant connect");

mysql_select_db($db);

$sql = "SELECT * FROM Articles";

$q = mysql_query($sql,$conn);

$num = mysql_num_rows($q);

for($i=0; $i<$num; $i++){

$title = mysql_result($q,$i,"title");

$author = mysql_result($q,$i,"author");

$abs = mysql_result($q,$i,"abstract");

$full = mysql_result($q,$i,"fulltext");

$smarty->append(array(

title => $title,

author => $author,

abstract => $abs,

fulltext => $full ));

}

$smarty->display("index.tpl");

?>

За столь широкую функциональность Smarty приходится платить ресурсами сервера и временем исполнения скрипта на его основе.

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

В результате сайт будет состоять из ядра - набора библиотек (классов), которые содержат в себе какие-то низкоуровневые действия, например работают с базой, – и компоненты, которые подключают эти библиотеки и, в нужном порядке, вызывают те или иные их методы. В чем положительная сторона такого подхода?

вы пишите специальные классы (объекты) ядра своего сайта, они никак не зависят от вывода на экран, а просто подготавливают и обрабатывают данные, тем самым обеспечивается высокая переносимость кода и возможность его повторного использования;

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

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

Общие классы

Безусловно, в каждом приложении есть набор классов, которые нужны всем, или большинству компонентов, например, класс для работы с базой. Как поступить в таком случае? И для этой проблемы в Smarty есть удачное решение. Сначала инициализируем класс Smarty:

<?php

/** Путь до Smarty */

define('SMARTY_DIR', '/smarty/');

/** Путь до Smarty шаблонов */

define('TEMPLATES', '/templates/');

/** Путь до Smarty компилированных шаблонов */

define('TEMPLATES_C', '/templates_c/');

require_once(SMARTY_DIR . 'Smarty.class.php');

$smarty = new Smarty;

$smarty->compile_check = TRUE;

$smarty->force_compile = TRUE;

$smarty->template_dir = TEMPLATES;

$smarty->compile_dir = TEMPLATES_C;

$smarty->plugins_dir[] = LIBS_PATH;

$smarty->caching = FALSE;

?>

Итак, Smarty готов к работе. Что необходимо сделать с общими классами, чтобы обеспечить доступ к ним внутри любого компонента?

Скажем, у нас есть несколько общих компонентов:

adodb – класс для работы с базой;

session – класс для работы с сессиями;

errors – класс для обработки ошибок;

variables – класс для хранения и обработки состояния массивов $_GET и $_POST.

Первым делом, нам необходимо создать объекты данных классов (параметры конструкторов зависят от вашей конкретной реализации). В целом, это делается стандартным образом:

<?php

require_once(CLASSES_DIR . '/variables.class.php');

$vars = new Variables();

require_once(CLASSES_DIR . '/errors.class.php');

$errors = new Errors($smarty);

require_once(CLASSES_DIR . '/security.class.php');

$security = new Security($adodb);

// и так далее...

?>

Объекты созданы и теперь необходимо обеспечить доступ к ним в любом компоненте нашего приложения. Для этого необходимо зарегистрировать данные объекты в Smarty:

<?php

$smarty->register_object('adodb', $adodb);

$smarty->register_object('vars', $vars);

$smarty->register_object('errors', $errors);

$smarty->register_object('security', $security);

?>

Для регистрации объектов мы используем метод Smarty register_object(). После чего ваш объект станет доступным везде, где он может понадобиться. Как «достать» нужный вам зарегистрированный объект мы рассмотрим в следующей части.

Функция «Компонент»

К текущему моменту Smarty ничего не знает о каких-либо компонентах, и нам нам надо научить его работать с ними. Для этого мы добавляем к синтаксису шаблонов новый тег – {component}. Чтобы Smarty научился обрабатывать этот тег – пишем простую функцию:

<?php

// Smarty function Component

//

// @author Feskov Kuzma

function smarty_function_component($params, &$smarty) {

$adodb = &$smarty->get_registered_object('adodb');

$vars = &$smarty->get_registered_object('vars');

$errors = &$smarty->get_registered_object('errors');

$security = &$smarty->get_registered_object('security');

if (empty($params['name'])) {

$params['name'] = 'site_view';

}

if (is_file(ADMIN_LIBS_PATH . '/' . $params['name'] . '.component.php')) {

require(ADMIN_LIBS_PATH . '/' . $params['name'] . '.component.php');

} else {

echo 'Component <strong>' . $params['name'] . '</strong> not found';

}

unset($adodb, $errors, $security, $vars);

}

?>

Давайте разберемся, что делает данная функция. Во-первых, она создает обработчик для нового тега – {component}, во-вторых, достает (get_registered_object()) и делает доступными вызванному компоненту зарегистрированные ранее общие объекты.

Немножко теории. Чтобы вызвать данную функцию к жизни, необходимо в любом шаблоне написать тэг {component}. Поскольку функция не выполняет никаких продуктивных действий, и служит исключительно диспетчером компонентов, просто написать {component} недостаточно, поскольку эта команда неинформативна. Конечно, функция не даст сбоя, и запустит принятый по умолчанию компонент 'site_view'. Каким образом уточнить, какой именно компонент вам требуется и как передать ему дополнительные параметры? Все очень просто, мы несколько измени вызов компонента в шаблоне:{component name='имя требуемого компонента' var1='значение параметра' var2='значение другого параметра'}

И так далее, как вы понимаете, name, var1, var2 – это дополнительные параметры для нашего компонента. Name, например, указывает имя компонента, который мы хотим вызвать, а остальные параметры – это дополнительные данные для вызываемого компонента, их количество может быть любым, ровно как и их имена. После того, как в шаблоне встретится указанный выше тег, произойдет вызов нашей функции, которая, в свою очередь, вызовет нужный вам компонент. Все дополнительные параметры будут доступны как в нашей функции так и в вызываемом компоненте, они будут содержаться в массиве $params, где ключ – это название параметра, а значение – соответственно – его значение.

Мы приняли, что файлы наших компонентов именуются следующим образом:name.component.php где name – это наш параметр name.

Функция ищет в указанной папке файл с именем, сформированным указанным образом и исполняет его. В случае отсутствия параметра name запускает компонент, назначенный по умолчанию, в противном случае – выдает ошибку.

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

Настало время посмотреть, что же у нас представляет собой компонент. Компонент выполняет роль диспетчера, он будет обрабатывать действия, которые вы ему определите, вызывая те или иные методы разных классов.

Давайте предположим, что наш компонент выводит новости на главную страницу. Новостей там может быть не более 5 за раз.

В шаблоне напишем так:

{component name='news' action='view' count=5 tpl='news_mainpage.tpl'}

Параметр name указывает на нужный нам компонент, action обозначает действие, которое требуется совершить, count – это фильтр количества новостей, и tpl – название шаблона, который будет использован для формирования вывода новостей на экран.

Теперь давайте посмотрим, как мог бы выглядеть наш компонент:

<?php

// News component

//

// @author Feskov Kuzma

// Подключаем необходимый нам класс

// и создаем объект

require_once(CLASSES_DIR . '/news.class.php');

$news = new News($adodb);

// Обрабатываем возможные действия

switch ($params['action']) {

// --- View news ---

case 'view':

// Получаем 5 последних новостей

$data = $news->NewsList($params['count']);

if (false === $data) {

// Выводим ошибку

$errors->ComponentErrPrint('Компонент news, действие ' . $params['action'], $news->ERROR);

}

// Проверяем - есть ли такой шаблон

if(is_file(TEMPLATES . '/' . $params['tpl'])) {

// Выводим новости на экран

$smarty->assign('data', $data);

$smarty->display($params['tpl']);

} else {

// Выводим ошибку

$errors->ComponentErrPrint('Компонент news, действие ' . $params['action'], 'Шаблон не найден');

}

break;

// --- Default action ---

default:

// Если никакого действия не задали, выводим ошибку

$errors->ComponentErrPrint('news_view', 'Неизвестное действие');

break;

}

?>

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

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

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

4. Торжество шаблонов: php-templates

Движок шаблонов со средними возможностями - переменные и блоки, но с самой большой скоростью работы, потому что сделан как модуль для php. Соревноваться в скорости с ним не может ни монстр Smarty, ни всякие классы *Template. Для установки придётся перекомпилировать Apache на сервере или вписывать модуль в php.ini под виндой.

Шаблон со списком товаров и ценами:

<html>

<head>

<title>Prices of ACME, Inc.</title>

</head>

<body>

<table border=1 cellspacing=0 cellpadding=2>

<tr>

<th>Product</th><th>Price</th>

</tr>

<tmpl:row>

<tr>

<td>{product}</td><td>{price}</td>

</tr>

</tmpl:row>

</table>

</body>

</html>

Код, достающий их из базы данных и вставляющий в шаблон:

<?php

/* Код подключения к MySQL опущен */

$template = tmpl_open("prices.html");

$sql = "SELECT product, price FROM Products ORDER BY product";

$result = mysql_query($sql) or die("SQL error: ". mysql_error());

while($data = mysql_fetch_assoc($result)) {

tmpl_iterate($template, "row");

tmpl_set($template, "row", $data);

}

echo tmpl_parse($template);

?>

Соседние файлы в папке example1