PHP: Systemy szablonów » aspiryna.net

PHP: Systemy szablonów

Autor: leafnode | Data: 28.08.2007, 11:05 | Kategoria: PHP

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).

Zobacz też



Zostaw komentarz

*
To prove that you're not a bot, enter this code
Anti-Spam Image