Kod PHP przeplatający się z tagami HTML wygląda bardzo nieczytelnie. Jest wiele metod na odseparowanie kodu PHP od kodu HTML. Jedną z takich metod są systemy szablonów.
Separować kod od treści można na przykład tak:
<?php
function title() {
echo 'tytuł';
}
function body() {
table();
}
function table() {
echo '<table>';
while (coÅ›) {
row(dane);
}
echo '</table>';
}
function row($dane) {
echo '<tr>';
echo '<td>';
echo $dane;
echo '</td>';
echo '</tr>';
}
?>
<html>
<head>
<title><?php title() ?></title>
</head>
<body>
<?php body() ?>
</body>
</html>
Mimo wszystko nie wyglÄ…da to najlepiej. Najepszym rozwiÄ…zaniem jest system template’ów (wzorców). W systemie takim tworzone sÄ… osobne pliki zawierajÄ…ce kod PHP i osobne zawierajÄ…ce kod HTML, zawierajÄ…ce jednak specjalne oznaczenia, gdzie należy wstawić dane przekazane przez PHP. Taki plik może przykÅ‚adowo wyglÄ…dać tak:
index.tpl
<html>
<head>
<title>{title}</title>
<meta name="description" content="{description}"/>
</head>
<body>
<table>
<tr>
<th>ID</th>
<th>Autor</th>
<th>Tytuł</th>
<th>Wydawnictwo</th>
</tr>
{table}
</table>
</body>
</html>
table.tpl
<tr>
<td>
{id}.
</td>
<td>
{autor}
</td>
<td>
{tytul}
</td>
<td>
{wydawnictwo}
</td>
</tr>
Na początek trzeba stworzyć klasę, która będzie przetwarzała wzorce. Trzeba się zastanowić jakich metod i pól klasa będzie potrzebowała. Najwygodniej będzie, jeśli konstruktor klasy będzie jako parametr przyjmował nazwę pliku wzorca. Niezbędna będzie metoda dodająca zmienną do podstawienia (a co za tym idzie także pole, w którym zmienne te będą przechowywane) oraz metoda zwracająca przetworzony wzorzec. Dla wygody można także dodać metodę, która od razu będzie wyświetlała wzorzec.
Tak więc na początek pola:
<?php
class Template {
var $tmpl;
var $dane;
}
?>
Konstruktor ma za zadanie wczytać plik ze wzorcem.
<?php
function Template ($name)
{
$this->tmpl = file_get_contents($name)); // Funkcja file_get_contenst dostępna jest
// w php od PHP 4.3.0
$this->dane = Array();
}
?>
Funkcja dodajÄ…ca dane do wzorca powinna przyjmować dane w dwóch postaciach: albo dwa parametry – nazwa i wartość, albo jeden parametr – tablica, w której nazwy zmiennych zapisane sÄ… jako klucze.
<?php
function add($name, $value = '')
{
if (is_array($name)) {
$this->dane = array_merge($this->dane, $name);
} else if (!empty($value)) {
$this->dane[$name] = $value;
}
}
?>
Powyższa metoda sprawdza, czy pierwszy z parametrów jest tablicÄ…. JeÅ›li tak, zostaje ona dołączona do istniejÄ…cych danych przy pomocy funkcji array_merge(). Podawanie do metody tablicy jest bardzo wygodne – umożliwia to bezpoÅ›rednie przekazanie wiersza odczytanego z bazy danych. JeÅ›li natomiast podane zostaÅ‚y dwa parametry, pierwszy z nich zostanie użyty jako klucz a drugi jako wartość tablicy z danymi.
Skoro sÄ… już dane i jest wzorzec, trzeba to połączyć, czyli stworzyć metodÄ™ wstawiajÄ…cÄ… dane do wzorca. Można to zrobić na wiele sposobów. Seria wywoÅ‚aÅ„ funkcji str_replace jest nieefektywna, gdyż dla każdego wywoÅ‚ania wzorzec musi być przeszukany od poczÄ…tku – dużo lepiej jest zrobić to przy pomocy wyrażeÅ„ regularnych. Przy pomocy funkcji preg_replace() można podmienić każde napotkane wyrażenie {zmienna} na zawartość tablicy o kluczu podanym w wyrażeniu.
<?php
function execute() {
return preg_replace('/{([^}]+)}/e', '$this->dane["\\1"]', $this->tmpl);
}
?>
Teraz wystarczy posklejać wszystko w całość.
<?php
class Template {
var $tmpl;
var $dane;
function Template ($name)
{
$this->tmpl = file_get_contents($name);
$this->dane = Array();
}
function add($name, $value = '')
{
if (is_array($name)) {
$this->dane = array_merge($this->dane, $name);
} else if (!empty($value)) {
$this->dane[$name] = $value;
}
}
function execute() {
return preg_replace('/{([^}]+)}/e', '$this->dane["\\1"]',
$this->tmpl);
}
}
?>
Teraz może mały przykład jak to wykorzystać. Zakładając, że klasa Template znajduje się w pliku template.inc.php:
test.php
<?php
include 'template.inc.php';
$tmpl = new Template('test.tmpl');
$tmpl->add('title', 'strona testowa');
$tmpl->add('autor', 'Leszek');
$tmpl->add('charset', 'iso-8859-2');
$dane = Array('imie'=> 'Franek', 'podpis'=>'sincerly yours');
$tmpl->add($dane);
echo $tmpl->execute();
?>
test.tmpl
<html>
<head>
<title>{title}</title>
<meta http-equiv="Content-type" content="text/html; charset={charset}" />
</head>
<body>
Cześć, nazywam się {autor}
To jest indywidualna strona stworzona tylko dla Ciebie, {imie}
{podpis}
<p style="text-indent: 30ex">{autor}
</body>
</html>
System taki można także zagnieżdżać, aby wyświetlać dane z tabeli.
test.php
<?php
include 'template.inc.php';
$res = mysql_query('select * from data');
while($row = mysql_fetch_array($res)) {
$rows = new Template('rows.tmpl');
$rows->add($row);
$table .= $rows->execute();
}
$tmpl = new Template('test.tmpl');
$tmpl->add('title', 'strona testowa');
$tmpl->add('charset', 'iso-8859-2');
$tmpl->add('table', $table);
echo $tmpl->execute();
?>
test.tmpl
<html>
<head>
<title>{title}</title>
<meta http-equiv="Content-type" content="text/html; charset={charset}" />
</head>
<body>
<table>
{table}
</table>
</body>
</html>
rows.tmpl
<tr>
<td>
{imie}
</td>
<td>
{nazwisko}
</td>
<td>
{adres}
</td>
</tr>
Przy użyciu tego systemu wzorców zmiana sposobu wyświetlania danych z bazy danych z tabelarycznego na rekordowy to kwestia usunięcia otwarcia tabeli z głównego wzorca i zmiany wzorca wyświetlającego dane.
RozwiÄ…zanie to jest bardzo proste, ale wystarcza dla wielu celów. Zaawansowane systemy wzorców, takie jak na przykÅ‚ad Smarty, umożliwiajÄ… umieszczenie we wzorcach pÄ™tli. Dodanie takich opcji wymaga już innej konstrukcji funkcji podstawiajÄ…cej dane do wzorca oraz samego wzorca. NiezbÄ™dne jest okreÅ›lenie bloku, który bÄ™dzie podlegaÅ‚ pÄ™tli, oraz danych – najÅ‚atwiej podać je w postaci tablicy. Jak to zrealizować – najepiej podejrzeć jak jest to zrealizowane w innych systemach.
Jeśli potrzebny jest system wzorców oferujący większe możliwości, można skorzystać z gotowych rozwiązań. Jednym z najlepszych pakietów jest Smarty Templates, dostępny pod adresem http://smarty.php.net/
Podstawianie danych do wzorca i wyÅ›wietlanie go za każdym żądaniem od klienta jest nieefektywne – operacja podstawiania jest stosunkowo dÅ‚ugotrwaÅ‚a a potrzeba ponownego generowania strony zachodzi tylko w dwóch przypadkach: kiedy zmienia siÄ™ wzorzec albo zmieniajÄ… siÄ™ dane. Dobrym rozwiÄ…zaniem jest zastosowanie klas typu Cache – jednej z dostÄ™pnych (np. zawartej w repozytorium PEAR – http://pear.php.net) lub napisanie wÅ‚asnej (o tym w osobnym artykule).


Tagi:
Zostaw komentarz