Strona główna
O mnie
Projekty
Publikacje
Linki
|
|
„ aawansowane możliwości Smarty" Autor: Adam Major
|
Wersja do druku
|
Artykul został pierwotnie opublikowany w magazynie PHP Solutions nr 1 (8/2003) |
www.phpsolmag.org |
Smarty jest jednym z najbardziej zaawansowanych systemów szablonów przeznaczonych dla języka
PHP. Charakteryzuje się duża szybkością działania oraz rozbudowaną funkcjonalnością wyróżniającą ten
produkt wśród wielu istniejących na rynku.
Systemy szablonów pozwalają na oddzielenie części prezentacyjnej aplikacji (HTML, grafika, JS, CSS)
od skryptów PHP, co zapewnia nieporównywalną wygodę tworzenia i modyfikacji programów oraz ich
przejrzystość. Podstawy posługiwania się Smarty oraz porównawczy test wydajnościowy konkurencyjnych
systemów szablonów znajdą czytelnicy w moim artykule zamieszczonym w Software 2.0 PHP Extra! nr 1 "PHP
starter kit" lub online pod adresem www.ivpro.net/szablony.htm.
Mechanizm cache
Jest kolejną funkcją po kompilowaniu szablonów zaprojektowaną w celu zwiększenia szybkości
działania serwisu oraz odciążenia serwera od zbędnej pracy. Zasada wykorzystania tego mechanizmu polega na
tym, aby wygenerowane strony, których treść zmienia się stosunkowo rzadko, zapisywać do przetworzonych już
wynikowych plików HTML. Tak przygotowane pliki wysyłane są do przeglądarki bez konieczności
wykonywania czasochłonnych operacji: skomplikowanych obliczeń, pobierania danych z bazy SQL oraz
przetwarzania szablonu.
Stosując ten mechanizm zachowujemy pełną wygodę i kontrolę nad szablonem poprzez ustawienie
ważności bufora oraz możliwość jego usunięcia w wybranej przez nas chwili. Przy każdym przetwarzaniu
skryptu, Smarty sprawdza czy nie został zmieniony szablon bazowy z którego utworzono plik cache oraz czy
bufor istnieje i ma przyszły termin ważności, jeśli któryś z tych warunków nie jest spełniony to automatycznie
jest tworzony od nowa.
Aby skorzystać z funkcji buforującej Smarty należy przygotować katalog w którym będą
przechowywane przetworzone do postaci HTML pliki bufora oraz dokonać konfiguracji w pliku
Smarty.class.php.
Katalog - nazwijmy go cache - najlepiej umieścić ponad DOCUMENT_ROOT serwera WWW, jeśli to
nie jest możliwe np.: z powodu braku takiej opcji u firmy hostującej, warto utworzyć go w głównym katalogu
naszego serwisu .
|
|
Rysunek 1. Sposób przetwarzania szablonów: a) standardowy, b) z mechanizmem cache
|
Musimy umożliwić zapis do cache dla użytkownika na którego prawach pracuje serwer
WWW (zwykle nobody lub http), jeśli mamy takie uprawnienia lub możemy poprosić administratora należy
nadać prawa 770 oraz zmienić właściciela katalogu na http:http, jeśli nie to musimy zadowolić się 777.
Zanim uruchomimy pierwszy przykład wykorzystujący mechanizm należy zmienić ustawienia kilku
opcji głównego pliku systemu szablonów. Położenie katalogu przeznaczonego na zbuforowane pliki ustawiamy
za pomocą zmiennej $cache_dir. W zasadzie na razie możemy zakończyć konfigurację. Jednakże, jeśli PHP
pracuje w trybie bezpiecznym (safe_mode) będziemy zmuszeni do wyłączenia tworzenia podkatalogów w cache
i tpl_c nadając zmiennej $use_sub_dirs wartość false. Podkatalogi te, pozwalają uniknąć powstawania dużej
ilości plików w jednym folderze, a tym samym przyspieszają odnalezienie pliku przez system operacyjny.
Zaczniemy od bardzo prostego przykładu, prezentującego różnicę w działaniu Smarty przy normalnym
przetwarzaniu szablonu oraz z udziałem mechanizmu cache. Tworzymy nieskomplikowany szablon o nazwie
cache.tpl i umieszczamy w katalogu przeznaczonym na szablony (w moim przypadku tpl).
Jeśli chcemy włączyć buforowanie danego szablonu, ustawiamy dwie zmienne obiektu $smarty,
$smarty->caching na wartość 2, co spowoduje możliwość lokalnego określenia czasu wygaśnięcia bufora w
sekundach (przy wartości 1 brane są ustawienia globalne z Smarty.class.php).
Drugą zmienną jest wspomniany wyżej czas życia zbuforowanego pliku w naszym przykładzie = 10. Odświeżając stronę kilkukrotnie możemy
zaobserwować działanie mechanizmu, który przez 10 sekund pobiera wygenerowany plik pomijając
podstawianie nowych zmiennych pod znaczniki, a po upływie ważności generowany jest nowy plik bufora.
Warto zauważyć, że skorzystanie z mechanizmu buforującego nie pociąga żadnych zmian w szablonie.
|
|
<html>
<body bgcolor="#FFFFFF">
Data: {$a_date}
<body>
</html>
Listing 1 Prosty szablon
<?php
include_once('Smarty.class.php');
$smarty = new Smarty;
$smarty->cache_lifetime = 10;
$smarty->caching = 2;
$smarty->assign('a_date', date('Y.m.d H:i:s'));
$smarty->display('cache.tpl');
?>
Listing 2 Zastosowanie mechanizmu cache
|
Buforowanie fragmentów stron
W praktyce zdarzają się sytuacje, kiedy chcemy buforować jedynie fragment strony, którego
generowanie trwa stosunkowo długo lub/i jego postać zmienia się rzadko, a nie możemy cachować całej strony,
ponieważ zawiera ona elementy, które muszą się zmieniać dynamicznie np. banery.
Doskonałym przykładem jest moduł ankiet, umożliwiający zbieranie opinii na przeróżne tematy od
czytelników naszego serwisu oraz prezentujący wyniki. Bardzo mały odsetek osób uczestniczy w głosowaniu
przez co wyniki nawet w serwisach o dużej oglądalności zmieniają się dość rzadko. Funkcjonalnie moduł taki
składa się z dwóch stron: formularza z pytaniem oraz wyników głosowania.
Ważną cechą Smarty, którą zastosujemy jest możliwość generowania kilku różnych buforów z tego
samego szablonu na podstawie wybranego przez nas parametru (np. identyfikatora klienta z bazy danych).
Tworzymy więc jeden szablon odpowiedzialny za wyświetlanie pytania oraz wyników głosowania.
Czy wyświetlać pytanie, czy wynik głosowania skrypt będzie decydował na podstawie zawartości
ciastka (cookie), które ustawiamy po oddaniu głosu. Oczywiście w przypadku ankiet poleganie wyłącznie na
mechanizmie cookie nie wystarczy aby utrudnić wielokrotne głosowanie, jednak ten artykuł pokazuje jedynie
uproszczoną ideę tworzenia takiego modułu.
Zadaniem kodu przedstawionego na listingu 4 jest wybór prezentowanej informacji: formularza ankiety
lub jej wyników na postawie zawartości ciastka o nazwie q_ans. Następnie posługujemy się metodą is_cached(),
która przyjmuje dwa argumenty: nazwę szablonu oraz identyfikator bufora. Właśnie dzięki temu
identyfikatorowi możemy tworzyć wiele instancji bufora dla tego samego szablonu. W przypadku, gdy właściwy
plik cache nie spełnia warunków wykorzystania: nie istnieje, stracił ważność lub zmieniono źródłowy szablon
(kryterium to jest sprawdzane jeśli zmienna $compile_check na wartość true) spełniony jest warunek i dołączany
plik mod_an.php. Zadaniem tego pliku jest pobranie informacji o pytaniu lub wynikach ankiety, obrobienie ich i
przyporządkowanie odpowiednich wartości pod znaczniki obsługiwane przez szablon z listingu 3.
Najistotniejszymi fragmentami kodu są linie zawierające metodę fetch(), której działanie jest podobne
do metody display() z tą różnicą, że przetworzony szablon nie jest wyświetlany, a zwracany. Dzięki połączeniu
jej z assign() całą przetworzoną zawartość mamy przypisaną do znacznika {$mod_an}, który umieszczamy w
dogodnym dla nas miejscu w głównym szablonie. Istotne jest, że dzięki zastosowaniu powyższej konstrukcji,
fetch() użyje zbuforowanej wersji lub zostaną podstawione nowe wartości poprzez dołączany plik mod_an.php.
Należy pamiętać o wyłączeniu mechanizmu buforującego za pomocą ustawienia zmiennej caching na 0,
co zapobiegnie buforowaniu pozostałej dynamicznej zawartości strony.
Bufory będą samoczynnie czyszczone po upływie 24 h od ich utworzenia, a proces regeneracji
uruchomi się przy wejściu pierwszej osoby na stronę. Jeśli chcemy skasować cache szablonu w wybranym przez
nas momencie powinniśmy posłużyć się metodą clear_cache(), która przyjmuje cztery parametry, jednak w
większości przypadków wystarczą nam dwa pierwsze: nazwa szablonu oraz opcjonalny identyfikator bufora. W
przykładowym module ankiet, czyszczenie cache wyników powinno się odbywać po zweryfikowaniu czy dany
użytkownik może głosować: poprzez
|
|
<table width=129 cellpadding=0 cellspacing=0>
<tr><td>
{if $mc != "res"}
<form action="vote.php" method=post>
<b>{$question}</b><br>
{section name=row loop=$row_cnt}
<input type=radio name=z value={$o_val[row]}>
{$o_name[row]}<br>
{/section}
<div align=center>
<input type=submit value="Głosuj" class=fsu>
</div>
</td></form></tr>
{else}
<b>{$question}</b><br>
<table width=116 cellpadding=1 cellspacing="0">
{section name=row loop=$row_cnt}
<tr><td>{$answers[row]}: {$scores_p[row]}</td>
</tr>
{/section}
</table></td></tr>
{/if}
</table>
Listing 3 Prosty szablon modułu ankiet
<?php
include_once('Smarty.class.php');
$smarty = new Smarty;
$q_id = 1;
$smarty->caching = 2;
$smarty->cache_lifetime = 86400;
if ($_COOKIE['q_ans'] == $q_id) {
if(!$smarty->is_cached('mod_an.tpl','res'))
{
$mc = 'res';
include('mod_an.php');
}
$smarty->assign('mod_an',
$smarty->fetch('mod_an.tpl','res'));
} else {
if(!$smarty->is_cached('mod_an.tpl'))
{
$mc = 'questions';
include('mod_an.php');
}
$smarty->assign('mod_an',
$smarty->fetch('mod_an.tpl'));
}
$smarty->caching = 0;
$smarty->assign('a_date', date('Y.m.d H:i:s'));
$smarty->display('main.tpl');
?>
Listing 4 Sterowanie buforami modułu
<html>
<body bgcolor="#FFFFFF">
Dane dynamiczne: {$a_date}
{$mod_an}
</body>
</html>
Listing 5 Szablon główny - main.tpl
|
sprawdzenie obecności cookie oraz porównanie kombinacji IP i IP Proxy
użytkownika z listą osób głosujących na daną ankietę w ciągu ostatnich 20 min. Jeśli warunki są spełnione
należy zwiększyć stosowną wartość dla tego głosowania (w bazie danych lub w pliku), wysłać ciastko
informujące o głosowaniu, skasować bufor wyników poleceniem $smarty->clear_cache('mod_an.tpl','res'); oraz
przekierować przeglądarkę na stronę z szablonem głównym.
Natomiast jeśli dodamy nową ankietę musimy skasować zarówno wyniki jak i formularz głosowania,
oczywiście w drugim przypadku pomijamy identyfikator bufora.
Mechanizm cache jest bardzo pożytecznym narzędziem, szczególnie jeśli prezentujemy na stronie
informacje, których przygotowanie jest bardzo pracochłonne dla serwera np. analiza statystyk. Dzięki niemu
generujemy stronę powiedzmy raz na godzinę w dodatku, następuje to tylko gdy jakiś użytkownik ją wywoła (i
minie termin ważności bufora).
Rozszerzanie funkcjonalności
Dzięki zaimplementowaniu systemu wtyczek (plugins), Smarty można bardzo prosto wzbogacić o nowe
modyfikatory, które będzie można wykorzystywać w identyczny sposób jak standardowe.
W przypadku serwisów wielojęzycznych, a zwłaszcza sklepów internetowych, istotna jest prezentacja
informacji o produktach w pełni dostosowana do specyfiki danego kraju. Oprócz opisów w danym języku,
widocznymi różnicami jest sposób zapisu daty oraz formatowania liczb (np. separator dziesiętny). Dostosowanie
tych elementów można obsłużyć bezpośrednio w skryptach PHP, jednak dużo wygodniejsze jest zrealizowanie
tego zadania w szablonach.
Modyfikator formatujący datę został już umieszczony standardowo, dopiszemy więc własny realizujący
formatowanie liczb w oparciu o funkcję PHP number_format(). Tworzenie modyfikatorów jest bardzo proste i
sprowadza się do utworzenia w katalogu plugins (lub innym zdefiniowanym na wtyczki Smarty) pliku o nazwie
modifier.nazwa_modyfikatora.php. W pliku takim tworzymy funkcję, której nazwa musi mieć postać
smarty_modifier_nazwa_modyfikatora. Zwracana wartość (poprzez return) funkcji zostanie podstawiona do
szablonu.
<?php
function smarty_modifier_number_format($number, $num_dec=null, $dec_sep=null,
$t_sep=null)
{
return number_format($number, $num_dec, $dec_sep, $t_sep);
}
?>
Listing 6 Modyfikator number_format
|
Modyfikator ten posiada 4 parametry, pierwszy jest zawsze dostarczany przez Smarty i przyjmuje
wartość przypisaną do znacznika lub przetworzoną przez poprzednie modyfikatory, jeśli takie operowały na
znaczniku. Smarty bowiem, umożliwia łączenie działania kilku modyfikatorów poprzez znak | np.
{$znacznik|upper|spacify} najpierw wartość zostanie przetworzona przez modyfikator upper, następnie wynik
tego działania zostanie podany do obróbki modyfikatorowi spacify.
Posługiwanie się nowym modyfikatorem przebiega tak samo jak standardowymi, poprzez wywołanie
{$znacznik|number_format} uzyskujemy obcięcie części dziesiętnej liczby. Parametry modyfikatora podajemy
oddzielając je za pomocą znaku :. Formatowanie stosowane w Polsce uzyskujemy poprzez użycie w szablonie
konstrukcji {$znacznik|number_format:2:',':' '}, natomiast anglosaskie {$znacznik|number_format:2:'.':','}.
Osoby preferujące całkowite oddzielenie standardowych wtyczek systemu od własnych rozszerzeń,
mogą składować je w osobnym katalogu o nazwie np. new_plugins. W tym celu należy dopisać w pliku
Smarty.class.php w tabeli $plugins_dir nową lokalizację katalogu z wtyczkami.
Filtry
Smarty wyposażono w system filtrów za pomocą, których możemy wpływać na szablon
przed jego przetwarzaniem (prefilter) lub oddziaływać na jego wynik przed kompilacją szablonu (postfilter) oraz
w chwili wysyłania ostatecznego rezultatu - filtry wyjścia (output filters). Filtry mogą być umieszczane
podobnie jak modyfikatory w katalogu przeznaczonym na wtyczki, w takim przypadku pliki muszą mieć nazwę
rodzaj.nazwa_filtra.php , gdzie rodzaj może przyjąć wartość prefilter, postfilter, outputfilter. Natomiast funkcje
odpowiednio nazwy smarty_rodzaj_nazwa_filtra. Istnieje także możliwość deklaracji funkcji filtra bezpośrednio
w skrypcie PHP i rejestracji jej poprzez jedną z metod register_*().
Zastosowanie filtrów może być bardzo różnorakie od usuwania z szablonów komentarzy HTML,
otaczanie sekcji JavaScript i CSS w razie konieczności znacznikami {literal} {/literal} poprzez modyfikację
wyniku przetwarzania, polegającą np. na zamianie znaku @ na (at) w adresach email.
Stworzymy prefilter, którego zadaniem będzie usuwanie komentarzy HTML z szablonów przed ich
przetwarzaniem. W katalogu plugins tworzymy plik prefilter.remove_comments.php, w którym zamieszczamy
funkcję przedstawioną na listingu 7.
Aby zweryfikować działanie prefilter'a użyjemy skryptu, którego zadaniem będzie podstawienie pod
znacznik {$komentarz} łańcuch znaków reprezentujący HTMLowy komentarz. Co pozwoli nam wykazać, że ten
typ filtrów rzeczywiście wykonywany jest przed rozpoczęciem przetwarzania szablonu, a tym samym przed
podstawianiem wartości pod znaczniki.
Załadowanie filtra odbywa się za pomocą metody load_filter(), która oczekuje dwóch parametrów:
pierwszy określa typ filtra, może przyjmować wartość: pre, post i output, natomiast drugi to jego nazwa.
W wyniku zadziałania tego skryptu otrzymamy stronę z komentarzem ustawionym przez metodę assign(),
natomiast zdefiniowane bezpośrednio w szablonie komentarze zostaną usunięte.
Warto zauważyć, że filtry nie oddziałują bezpośrednio na pliki z szablonami, a jedynie na postać
skompilowaną lub
|
|
<?php
function smarty_prefilter_remove
_comments($source, &$smarty)
{
return preg_replace('/<--.*-->/', '', $source);
}
?>
Listing 7 Prefilter remove_comments
<html>
<body>
<!-- komentarz 1 -->
{$komentarz}
<!-- komentarz 2 //-->
lt;/body>
<html>
Listing 8 Szablon prezentujący działanie prefilter'a
<?php
include_once('Smarty.class.php');
$smarty = new Smarty;
$smarty->assign('komentarz', '');
$smarty->load_filter('pre', 'remove_comments');
$smarty->display('prefiler.tpl');
?>
Listing 9 Uruchomienie prefilter'a
|
zmiany są dokonywane tuż przed samym wyświetleniem strony.
Podsumowanie
Smarty dysponuje bardzo dużą funkcjonalnością, a dzięki technice dołączenia własnych wtyczek,
potrafi sprostać rozwijającym się potrzebom. Dodatkowo system ten przy zapewnieniu odpowiednich warunków
jest jednym z najszybszych silników szablonów dla PHP. Cechy te, a także stały rozwój Smarty sprawia, że
może on być stosowany w dużych wymagających serwisach.
Warto nadmienić, że wydajność systemu można podnieść aż o ok. 7% usuwając wszelkie komentarze
(zostawiając tylko informacje o autorach) z plików wchodzących w jego skład.
Mam nadzieję, że ten artykuł oraz jego pierwsza część, zachęciły czytelników do zastosowania Smarty
w swoich projektach, a Tych z Państwa, co używają innych rozwiązań szablonowych do przejścia na Smarty.
szablony2.zip (65 KB) - Listingi do artykułu
Artykul został pierwotnie opublikowany w magazynie PHP Solutions nr 1 (8/2003) |
www.phpsolmag.org |
|