Dla przykładu, plik z szablonem(szablon.tpl):
Cytat:
<HTML>
<HEAD>
<TITLE>{TITLE}</TITLE>
</HEAD>
<BODY>
{TEXT}
</BODY>
</HTML>
I by go użyć będziemy potrzebowali tylko takiego małego kawałku kodu:
Kod:
<?php
// [...] wcześniejsza część skryptu
$templates->load('szablon'); // wgrywamy plik z szablonem
$templates->blocks[] = array ('TITLE' => $page_title, 'TEXT' => $text); // ustalamy bloki do zamiany
$templates->parse(); // parsujemy kod HTML
$templates->show_result(); // wyświetlamy wynik
// [...] dalsza część skryptu
?>
To było najprostsze zastosowanie mojego parsera. Dodatkowe atuty parsera to:
- możliwość wczytania wielu plików z szablonami i nadania im odpowiednich bloków do zamiany, a dopiero poźniejsze sparsowanie całości
- wyświetlanie wyników wszystkich parsowań, pojedyńczego parsowania lub parsowań z pewnego przedziału
Artykuł Przedstawia kolejne etapy tworzenia takiego parsera.
ETAP 1
Zadanie: Parser zostanie napisany obiektowo(czyt. z zastosowaniem klas), zastanówmy się więc najpierw jakie powinien posiadać funkcje(operacje) i zmienne(atrybuty).
Wynik:
Stałe(definiowane poza klasą):
- F_TPL - przechowuje nazwę katalogu, w którym znajdują się szablony.
Atrybuty:
- $last_loaded - przechowuje nazwę ostatnio wczytamego pliku.
- $unparsed - przechowuje niezamieniony kod stron,
- $parsed - przechowuje zamieniony kod stron,
- $blocks - przechowuje bloki do zamiany.
Operacje:
- load() - wczytuje szablon(kod strony) i zapisuje go jako kolejny element tablicy $unparsed
- parse() - parsuje szablon i zapisuje wynik swojego działania jako kolejny element tablicy $parsed
- show_result() - wyświetla sparsowane szablon, w zależności od podanego parametru, wyświetla jeden szablon, szablony z podanego przedziału, lub jeśli nie podaliśmy parametru wyświetla wszystkie sparsowane szablony.
ETAP 2
Zadanie: Tworzymy kodowy zarys projektu.
Wynik:
Kod:
<?php
class Templates
{
var $unparsed = array ();
var $parsed = array ();
var $blocks = array();
var $last_loaded;
function load()
{
} #end function load()
function parse()
{
} #end function parse()
function show_result()
{
} #end function show_result()
} #end class Templates
define('F_TPL','tpls/');
?>
ETAP 3
Zadanie: Tworzymy funkcję otwierająca plik z szablonem.
Argumenty funkcji:
- funckja pobiera nazwę pliku do odczytu o rozszerzeniu .tpl
Działanie: Otwieramy plik do odczytu i zapisujemy całą jego zawartość jako kolejny element tablicy $unparsed.
Wykonanie:
1) Sprawdzamy czy ostatnio nie był wczytany ten sam plik, jeśli tak dodajemy nowy element to tablicy $unparsed o wartości ostatnio wczytanego szablonu, jeśli nie kontynuujemy działanie skryptu.
2) Sprawdzamy czy plik istnieje za pomocą funkcji file_exists(), która pobiera jako pierwszy parametr ścieżkę i nazwę pliku, jeśli tak wykonujemy dalszy skrypt, a jeśli nie wyskakuje błąd.
3) Blokujemy plik do odczytu za pomocą funkcji flock(), która jako pierwszy parametr pobiera identyfikator pliku, a jako drugi cyfrę oznaczająca dane działanie(dla zablokowania pliku jest to liczba 2).
4) Otwieramy plik za pomocą funkcji fopen(), która jako pierwszy parametr pobiera ścieżkę i nazwę pliku do otworzenia, a jako drugi tryb otworzenia pliku(w tym przypadku tryb odczytu: r od read).
5) Wczytyjemy całą zawartość pliku z szablonem za pomocą funkcji fread, która jako pierwszy parametr pobiera identyfikator pliku, a jako drugi wielkość danych jaką ma pobrać funkcja, po użyciu funkcji file_size() działającej na tym pliku, otrzymamy wielkość pliku, która zostanie zwrócona i wstawiona jako drugi parametr.
6) Zapisujemy wczytaną wartość jako nowy element w tablicy $unparsed.
7) Odblokowujemy plik do odczytu za pomocą funkcji flock(), która jako pierwszy parametr pobiera identyfikator pliku, a jako drugi cyfrę oznaczająca dane działanie(dla odblokowania pliku jest to liczba 3).
Wynik:
Kod:
<?php
function load($plik)
{
if($plik == $this->last_loaded)
{
$this->unparsed[] = end($this->unparsed);
}
elseif(file_exists(F_TPL.$plik.'.tpl'))
{
$file = @fopen(F_TPL.$plik.'.tpl',r);
flock($file, 2);
$this -> unparsed[] = fread($file,filesize(F_TPL.$plik.'.tpl'));
flock($file, 3);
$this->last_loaded = $plik;
}
else
echo 'Plik ' .$plik. ' nie istnieje.';
} #end function load()
?>
ETAP 4
Zadanie: Tworzymy funkcję parsującą szablon.
Działanie: Zamieniamy bloki między { i } na tekst podany w tablicy $blocks.
Wykonanie:
1) Wyszukujemy w szablonie ciągi znaków znajdujących się pomiędzy { i } i zapisujemy je w tablicy $found, za pomocą funkcji preg_match_all, która wykorzystuje perlowskie wyrażenia regularne, a znalezione ciągi zapisuje do tablicy.
2) Dla wszytskich znalezionych bloków, wyszukuje treść do zamiany z wielo wymiarowej tablicy $blocks o wymiarze odpowiednim dla danego szablonu i zamienia ją za bloki w szablonie za pomocą funkcji str_replace().
3) Sparsowany szablon zapisuje do zmiennej $template.
4) Po sparsowaniu wszystkich bloków w szablonie zapisuje w całości sparsowany szablon jako nowy element tablicy $parsed.
Czynności od 1 do 4 przeprowadzane są dla każdego z szablonów.
Funkcja foreach() działa w ten sposób iż każdy element tablicy zapisuje do nowej tablicy(w tym przypadku $this->unparsed as $template) i dla każdego elementu z nowej tablicy wykonuje odpowiedni kod zawarty między { i }.
Wynik:
Kod:
<?php
function parse()
{
$i=0;
foreach ($this->unparsed as $template)
{
$found = array();
if(preg_match_all("#\{(.+?)\}#is", $template, $found))
{
foreach($found[1] as $block)
{
$block_name = '{'.$block.'}';
$block_values = $this -> blocks[$i][$block];
$template = str_replace($block_name, $block_values, $template);
}
}
$this -> parsed[] = $template;
$i++;
}
} #end function parse()
?>
ETAP 5
Zadanie: Tworzymy funkcję wyświetlająca wyniki parsowania.
Działanie: Wyświetlamy wszystkie sparsowane szablony lub wyświetlamy jeden sparsowany szablon, lub wyświetlamy szablony z podanego przedziału.
Wykonanie:
1) Sprawdzamy czy dane o wyświetlaniu szablonów są poprawne, tzn. czy liczba zaczęcie jest mniejsza od liczby zakończenia, czy liczby zakończenia i początku są większe lub równe 0 i czy liczby końca nie jest większa od liczby wszystkich szablonów, jeśli wszystko jest poprawne wyświetlamy szablony z podanego przedziału.
2) Sprawdzamy czy liczba wyświetlonego szablonu jest równa lub większa od 0 i mniejsza lub równa od liczby szablonów, jeśli tak zostaje wyświetlony podany szablon.
3) W przeciwnym wypadku zostają wyświetlone wszystkie szablony od początku do końca.
Wynik:
Kod:
<?php
function show_result($which="all",$to=0)
{
if($which >= 0 && $to >= 0 && $to <= count($this->parsed) && $which != 'all')
{
if($which < $to)
{
while($which <= $to)
{
echo $this->parsed[$which];
$which++;
}
}
else
{
while($which >= $to)
{
echo $this->parsed[$which];
$which--;
}
}
}
elseif($which != 'all')
{
echo $this->parsed[$which];
}
else
{
foreach($this->parsed as $parsed)
{
echo $parsed;
}
}
} #end function show_result()
?>
No to całą klasę mamy napisaną, teraz przejdźmy do praktycznego zastosowania naszej klasy. Oto cała nasza klasa:
Kod:
<?php
class Templates
{
var $unparsed = array ();
var $parsed = array ();
var $blocks = array();
var $last_loaded;
function load($plik)
{
if($plik == $last_loaded)
{
$this->unparsed[] = end($this->unparsed);
}
elseif(file_exists(F_TPL.$plik.'.tpl'))
{
$file = @fopen(F_TPL.$plik.'.tpl',r);
flock($file, 2);
$this -> unparsed[] = fread($file,filesize(F_TPL.$plik.'.tpl'));
flock($file, 3);
$this->last_loaded = $plik;
}
else
echo 'Plik ' .$plik. ' nie istnieje.';
} #end function load()
function parse()
{
$i=0;
foreach ($this->unparsed as $template)
{
$found = array();
if(preg_match_all("#\{(.+?)\}#is", $template, $found))
{
foreach($found[1] as $block)
{
$block_name = '{'.$block.'}';
$block_values = $this -> blocks[$i][$block];
$template = str_replace($block_name, $block_values, $template);
}
}
$this -> parsed[] = $template;
$i++;
}
} #end function parse()
function show_result($which="all",$to=0)
{
if($which >= 0 && $to >= 0 && $to <= count($this->parsed) && $which != 'all')
{
if($which < $to)
{
while($which <= $to)
{
echo $this->parsed[$which];
$which++;
}
}
else
{
while($which >= $to)
{
echo $this->parsed[$which];
$which--;
}
}
}
elseif($which != 'all')
{
echo $this->parsed[2];
}
else
{
foreach($this->parsed as $parsed)
{
echo $parsed;
}
}
} #end function show_result()
} #end class Templates
define('F_TPL','tpls/');
?>
A to jej praktyczne zastosowanie
Kod:
<?php
include('templates.class.PHP'); // wczytujemy plik z klasą
$templates = new Templates; // tworzymy nowy obiekt klasy Templates
$templates->load('main_category'); // wczytujemy nowy szablon
$tempaltes->blocks[] = array ('CATEGORY' => 'Kategoria'); // bardzo ważne by po każdym wczytaniu dodać nową tablicę do tablicy $blocks
// nazwę bloku wpisujemy po lewej stronie bez klamer, a wartość do zamiany po =>
// jeśli nie potrzebujemy zamieniać żadnych bloków wystarczy wpisać "" => ""
$templates->load('menu');
$templates->blocks[] = array ('' => '');
$templates->parse(); // parsujemy szablony
$templates->show_result(); // wyświetlamy wyniki
?>
Powodzenia w dalszej modyfikacji i używaniu skrypty, wszelkie błędy i nie jasności proszę zgłaszać na forum.
Cały kod źródłowy wraz z testowymi szablonami i artykułem dostępny jest w dziale download=>Skrypty zespołu phpworld