Šablonovací systém Smarty

Transkript

Šablonovací systém Smarty
Šablonovací systém Smarty
Josef Toman
31. března 2008
1
Úvod do problematiky
Asi každý, kdo někdy vytvářel nějaký větší web s netriviálním zapojením php, dospěl do
stavu, kdy byl jeho kód velmi nepřehledný a těžko čitelný. Bloky html značek se střídají s
kusy php kódu, všude samé echo. Moudřejší programátoři v takové chvíli začínají používat
postupy, které alespoň částečně zlepší situaci. Vzniká řada funkcí, které generují tu či onu
část stránky, web se modularizuje. Výsledek, který se nakonec dostane do browseru, je tak
rozmělněn v bezpočtu souborů a funkcí. Pokud v tuto chvíli přijde k projektu designér, aby
dal webu novou tvář, nemá šanci na úspěch.
Šikovní grafici většinou neumí a nechtějí programovat, programátoři na druhou stranu
nezřídka grafickou stránku ignorují nebo jí přímo opovrhují. Při prostém míchání html a
php se však obě role významně prolínají. Pokud by programátor a designér byly skutečně
dvě různé osoby, museli by úzce spolupracovat a výsledná produktivita by byla nízká.
Tento problém je potřeba řešit tzv. oddělením vzhledu od logiky. Ideální je takový stav,
kdy programátor a designér mohou pracovat zcela nezávisle. Z teoretického hlediska totiž
stačí specifikovat, jaké objekty bude stránka obsahovat, co má být jejich obsahem a jakou
mají mít funkci. Úloha návrháře je potom následující. Vytvoří vzhled stránky a na konkrétní
místa umístí data, o kterých v tuto chvíli pouze vágně prohlašme, že jsou „někde nachystanáÿ.
Programátor na druhou stranu píše program, který v závislosti na vstupu (proměnná $_POST,
URL, . . . ) generuje požadovaný výstup. To dokáže i za předpokladu, že v životě neviděl html
a nerozezná růžovou barvu od zelené.
2
Dostupná řešení
Od motivace se nyní posuneme k řešením, která jsou dnes k dispozici. Možným východiskem
je využití formátu xml. Ten byl již od začátku navržen k uchovávání dat. Spojením s xslt
šablonami dostaneme způsob, jak vzhled (xslt šablona) oddělit od dat (xml soubor). Je
ovšem pravdou, že jazyk xsl nemůže bezezbytku nahradit php a tedy veškerou logiku, která
řídí web v jeho úplnosti. Navíc vyjadřovací způsob jazyka xsl je eufemicky řečeno velmi
exotický, obtížně pochopitelný a i po překonání těchto obtíží bývá výsledná šablona těžko
čitelná.
Další možností jsou šablonovací systémy, kterých dnes již existuje několik. Jedním z nich
je systém Smarty, kterým se budeme zabývat ve zbytku članku. Mezi systémy stejného druhu
1
vyniká jak snadným a intuitivním použitím, tak i výběrem nabízených funkcí. Jeho základním
stavebním kamenem jsou šablony, což není nic jiného než standardní (x)html soubor1 obohacený o Smarty tagy. Při návrhu šablony lze (mimo jiné) použít proměnné, které obsahují
potřebná data. Podívejme se na jednoduchý příklad on-line novinových článků.
Představme si novinový článek, který se skládá z titulku, úvodu, těla a jména autora. Tyto
elementy implicitně neobsahují žádnou informaci o způsobu svého zobrazení. Jejich obsah je
aplikací (php kód) předán do šablony2 . Designér potom navrhne šablonu zobrazující články
s využitím běžných html tagů, kaskádových stylů atd. a na příslušná místa pomocí Smarty
tagů vloží odpovídající obsah.
Rozhodne-li se někdy programátor, že změní způsob generování obsahu, návrhář šablony
to ani nepozná, natož aby musel cokoliv měnit. Naproti tomu když se jakkoliv změní šablona,
a tím i vzhled, neznamená to pro programátora žádnou práci navíc.
3
Vlastnosti systému
Systém Smarty je napsán v php3 . Lze na něj pohlížet jako na knihovnu, která implementuje
objekt Smarty, se kterým může programátor pracovat. Vše funguje velmi rychle, jelikož šablony se před zobrazením kompilují4 . K opětovné kompilaci dochází pouze tehdy, dojde-li ke
změně šablony.
Systém je velmi konfigurovatelný. Lze definovat vlastní sekvenci znaků, která v šabloně
uvozuje Smarty tag. Snadno lze vytvářet nové funkce, které jsou pak dostupné návrhářům
šablon. Smarty umožňuje práci s konfiguračními soubory. Jedním z jejich možných použití
je přehledná správa různých jazykových mutací webu. Šablony umožňují vkládání („includováníÿ) dalších šablon.
Kromě proměnných, které mohou být jak atomické, tak strukturované, lze v šablonách
používat mnoho dalších věcí. Kromě předdefinovaných funkcí jsou dostupné konstrukce typu
if/then/else a primitivní cykly. Obojí s neomezeným zanořováním. Navíc lze přímo do
šablon vkládat php kód, což je však na druhou stranu nedoporučované a většinou i zbytečné.
3.1
Instalace
Celá procedura je velmi jednoduchá. Stačí stáhnout distribuci Smarty a příslušné soubory
vybalit na vhodné místo. V php kódu je třeba nastavit konstantu SMARTY_DIR5 a vytvořit
instanci objektu Smarty. Dále je možné konfigurovat adresáře se šablonami, zkompilovanými
šablonami atd., systém ale funguje i bez toho.
3.2
Konkrétní příklad použití
Podívejme se na jednoduchý příklad. Vytvořená stránka má za úkol pozdravit uživatele zvoleným jazykem. Začneme php kódem (Příklad 1).
Čistě technicky může jít o jakýkoliv jiný obsah, důležité jsou pouze Smarty tagy.
Pravděpodobně jako čtveřice pojmenovaných proměnných.
3
Vyžaduje verzi 4.0.6 nebo vyšší
4
Výsledkem kompilace je opět php skript, jak už ale napovídá slovo kompilace, není příliš čitelný.
5
To není nutné v případě, že potřebné soubory jsou „vidětÿ.
1
2
2
<? php
require(’Smarty.class.php’);
$smarty = new Smarty;
$lang = get_lang();
$smarty->assign(’lang’, $lang);
$smarty->display(’index.tpl’);
?>
Příklad 1: obsah souboru index.php
Takto bude vypadat konfigurační soubor greetings.cfg (Příklad 2), ve kterém jsou
uloženy pozdravy v různých jazycích.
[en]
greeting
[cs]
greeting
[fr]
greeting
[gr]
greeting
[hu]
greeting
= "Hello"
= "Ahoj"
= "Salut"
= "Hallo"
= "Szia"
Příklad 2: obsah souboru greetings.cfg
A nakonec šablona index.tpl (Příklad 3), která vyrobí výsledný vzhled.
{ config_load file="greetings.cfg" section=$lang scope="global" }
<h1 style="color: red;">{ #greeting# }</h1>
Příklad 3: obsah souboru index.tpl
Jak je vidět, veškeré formátování se skutečně odehrává až v šabloně (červený nadpis
úrovně 1) a jakákoliv změna by neměla vliv na ostatní soubory.
4
4.1
Psaní šablon
Základní syntaxe
Všímavější již jistě ví, že podobně jako se pro html tagy používají znaky <>, tak u Smarty
jsou to složené závorky {}. Ještě všímavější čtenáři si mohou vzpomenout, že také lze stanovit
jiné znaky či sekvence znaků. Navíc by ještě mohlo docházet ke konfliktům s úseky javascriptu
nebo css, proto Smarty obsahuje tag literal, jehož obsah zůstává při interpretaci šablony
(kompilaci) nedotčen. Vše, co se nachází mimo složené závorky, je ponecháno beze změny.
V šablonách je možné psát i komentáře, a to tímto způsobem: {* Toto je komentář *}
S proměnnými se ve Smarty pracuje velmi podobně jako v php. Rovněž jsou uvozeny
znakem $, povoleno je indexování polí a lze přistupovat k metodám a proměnným objektů.
3
Výjimkou jsou proměnné z konfiguračních souborů, ty musí být obklopeny znakem # tak, jak
je vidět v příkladu 3.
Zápis funkcí je jednoduchý. Za otevírací závorkou je jméno volané funkce, následuje seznam parametrů oddělených mezerami tak, jak ukazuje toto schéma:
{ funcname attr1="val" attr2="val" }
Přímo v šabloně je možné zapisovat i matematické výrazy, např.:
{ $foo->bar - $bar[1] * $baz->foo->bar() - 3 * 7 }
4.2
Proměnné
Smarty rozeznává tři druhy proměnných. První typ tvoří proměnné předané z php společně
s těmi, které byly definovány až v šabloně. Jejich chování je stejné. K dispozici jsou atomické proměnné, standardní i asociativní pole libovolné hloubky a v neposlední řadě vnitřní
proměnné objektů. Použití těchto proměnných shrnuje příklad 4.
<?php
$smarty = new Smarty;
$smarty->assign(’Contacts’,
array(’fax’ => ’555-222-9876’,
’email’ => ’[email protected]’,
’phone’ => array(’555-444-3333’, ’555-111-1234’)));
$smarty->display(’index.tpl’);
?>
...
{$Contacts.fax}<br />
{$Contacts.email}<br />
{$Contacts.phone[0]}<br />
{$Contacts.phone[1]}<br />
...
555-222-9876<br />
[email protected]<br />
555-444-3333<br />
555-111-1234<br />
Příklad 4: použití proměnných - php, šablona a výstup
Proměnné z konfiguračních souborů jsme probrali již dříve a zbývá dodat pouze to, že k
nim lze přistupovat pomocí speciální proměnné $smarty.config. Tím se dostáváme k vyhrazené proměnné $smarty, pomocí které lze přistupovat k řadě interních hodnot, hodnotám z
polí GET, POST, SERVER atd. a několika dalším údajům. Jako sebevysvětlující příklady uveďme
$smarty.now a $smarty.version.
4
4.3
Modifikátory
Zajímavou oblastí návrhu šablon jsou modifikátory. Ve své podstatě jsou to pouze převlečené funkce, jejich zápis je však tímto způsobem intuitivní a přehledný narozdíl od typické
závorkové notace. Modifikátory lze uplatnit na proměnné, funkce a řetězce. Za výraz určený
k modifikaci napíšeme znak | následovaný jménem modifikátoru s případnými parametry,
které jsou odděleny dvojtečkou. Modifikátory je možné skládat za sebe v libovolném pořadí.
Jako příklad poslouží modifikátory k proložení mezerami6 a oříznutí (Příklad 5).
$text = "Don’t worry, be happy!";
...
{ $text|spacify|truncate:15 }<br />
{ $text|truncate:15|spacify }<br />
...
D o n ’ t
D o n ’ t
w o<br />
w o r r y ,
b e</br>
Příklad 5: použití modifikátorů - php, šablona a výstup
4.4
Interní funkce
Smarty rozeznává dva druhy funkcí. Interní funkce jsou základními stavebními kameny systému a nelze je běžným způsobem měnit. Dále si každý programátor může vytvořit své
uživatelské funkce a snadným způsobem je přidat k ostatním. Smarty již ve své základní
distribuci obsahuje řadu uživatelských funkcí. Nyní si ukážeme několik interních a posléze
uživatelských funkcí.
config load(file, section, scope)
Slouží k zavedení proměnných z konfiguračního souboru. Je možné určit konkrétní sekci (viz.
příklad 2) a rozsah platnosti těchto proměnných.
foreach(from, item, key, name), foreachelse
Cyklus přes jedno asociativní pole určené parametrem from. Item je název proměnné, která
bude v každém cyklu obsahovat příslušná data. Pokud je to zapotřebí, lze v každé iteraci
použít i příslušný klíč - k tomu slouží parametr key. Tento cyklus lze použít pouze pro jednu
úroveň pole, nicméně smyčky lze zanořovat do sebe. konkrétní použití ukazuje příklad 6.
Celý cyklus lze pojmenovat a prostřednictvím proměnné $smarty potom přistupovat k
dalším užitečným informacím o cyklu. Zmiňme třeba číslo aktuální iterace nebo celkový počet
iterací celého cyklu7 .
6
7
Nebo jiným specifikovaným řetězcem
Tento údaj je k dispozici, i když ještě cyklus neskončil
5
Nepovinný blok foreachelse je vykonán tehdy, když v předchozím bloku foreach nedošlo ani k jediné iteraci.
$smarty->assign("contacts", array(
array("phone" => "1", "fax" => "2", "cell" => "3"),
array("phone" => "555-444", "fax" => "555-333", "cell" => "760-123")));
...
{foreach name=outer item=contact from=$contacts}
{foreach key=key item=item from=$contact}
{$key}: {$item}<br>
{/foreach}
{/foreach}
..
phone: 1<br>
fax: 2<br>
cell: 3<br>
phone: 555-4444<br>
fax: 555-3333<br>
cell: 760-1234<br>
Příklad 6: příklad použití funkce foreach
include(file, assign, [variable, ...])
Funkce vkládající jinou šablonu. Povinným parametrem je jméno souboru. Také je možné
přidat parametr assign, který určí jméno proměnné, do které se uloží obsah šablony místo
zobrazení na místě funkce include. Všechny proměnné aktuální šablony jsou viditelné i ve
vkládané šabloně. Do volání funkce lze navíc zahrnout libovolné množství dalších parametrů,
které budou vystupovat jako lokální proměnné ve vkládané šabloně a budou mít přednost
před proměnnými stejného jména.
if/elseif/else
Příkaz if funguje stejně jako v php. Používá i stejné operátory a přidává několik dalších,
které jsou užitečné při návrhu šablony.
section(name, loop, start, step, max, show), sectionelse
Druhá možnost, jak cyklem projít pole. Narozdíl od funkce foreach se více blíží příkazu
for, jak ho známe z běžných programovacích jazyků. Povinnými parametry jsou name (jméno
indexu) a loop (pole). Při běžném použití bez dalších parametrů smyčka projde všechny
hodnoty daného pole, které tak jako jediné určuje, kolik iterací se vykoná. Parametry start
a step mají očekávaný význam. Údaj max určuje maximální počet operací, a pokud show
není nastaven na nepravdu, bude výsledek příkazu section normálně zobrazen. V opačném
6
případě (a nebo pokud nedošlo ani k jedné iteraci) se vykoná blok sectionelse. Možnosti
této funkce ukazuje příklad 7.
{section name=cust loop=$customers}
<p>id: {$customers[cust].id}<br>
name: {$customers[cust].name}<br>
address: {$customers[cust].address}<br>
{section name=contact loop=$contact_type[cust]}
{$contact_type[cust][contact]}: {$contact_info[cust][contact]}<br>
{/section}
</p>
{/section}
...
<p>id: 1000<br>
name: John Smith<br>
address: 253 N 45th<br>
home phone: 555-555-5555<br>
cell phone: 555-555-5555<br>
e-mail: [email protected]<br>
</p>
<p>id: 1001<br>
name: Jack Jones<br>
address: 417 Mulberry ln<br>
home phone: 555-555-5555<br>
cell phone: 555-555-5555<br>
e-mail: [email protected]<br>
</p>
Příklad 7: příklad použití funkce section
I v případě funkce section lze pomocí jejího jména a proměnné $smarty přistupovat k
interním hodnotám o cyklu, a to jak během jeho provádění, tak i po skončení smyčky.
4.5
Uživatelské funkce
assign(var, value)
Slouží k přiřazení hodnoty proměnné přímo při zpracovávání šablony. Oba parametry jsou
pochopitelně povinné.
cycle(name, values, ...)
Další funkce určená k procházení polí, která má ale narozdíl od ostatních jedno výhodné
použití. Znázorňuje ho příklad 8.
7
{section name=rows loop=$data}
<tr bgcolor="{cycle values="#eeeeee,#d0d0d0"}">
<td>{$data[rows]}</td>
</tr>
{/section}
...
<tr bgcolor="#eeeeee">
<td>1</td>
</tr>
<tr bgcolor="#d0d0d0">
<td>2</td>
</tr>
<tr bgcolor="#eeeeee">
<td>3</td>
</tr>
Příklad 8: příklad použití funkce cycle
eval(var, assign)
Tato funkce interpretuje proměnnou var, jako by to byla součást šablony. To je nutné v
případě, že obsahem proměnné jsou mimo jiné i Smarty tagy. Pokud je vyplněn parametr
assign, bude do proměnné zvoleného jména přiřazen výsledek funkce místo normálního zobrazení.
A kdy se něco takového hodí? Například může být potřeba umístit Smarty tagy do dat
v konfiguračním souboru nebo do proměnných předávaných z php. Jiným příkladem je souběžné použití Smarty a xml+xslt. Výstupem xsl šablony může být text se Smarty tagy.
Pokud je tento výstup předáván šabloně prostřednictvím php, musí být použita funkce eval8 .
html checkboxes(name, values, output, selected, options, ...)
Tato funkce vytvoří skupinu zaškrtávacích políček. Data lze zadat dvojím způsobem. Buď
dvěma poli values a output nebo jedním asociativním polem options. Pomocí parametru
selected lze zařídit, aby některá políčka byla rovnou zaškrtnuta. Výstup funkce je kompatibilní s xhtml. Použití viz. příklad 9
Smarty dále obsahuje i další funkce pro automatické vytváření formulářových prvků. Jsou
to html_radios a html_options, jejichž výstupem je skupina přepínačů, respektive seznam
možností pro element <select>.
html table(loop, cols, rows, ...)
Pomocí funkce html_table lze vytořit jednoduchou tabulku. Jediným povinným parametrem
je loop, což je pole hodnot, které mají být zobrazeny v tabulce. Pozor, jde o jednorozměrné
pole. Rozměry tabulky jsou dány parametry cols a rows. Stačí pouze druhý z nich, jelikož
8
Toto není umělý příklad, popsaná situace skutečně vznikla, když jsem vyvíjel jeden web.
8
$smarty->assign(’customers’, array(
1000 => ’Joe Schmoe’,
1001 => ’Jack Smith’,
1002 => ’Jane Johnson’,
1003 => ’Charlie Brown’));
$smarty->assign(’cust_id’, array(1001, 1003));
...
{html_checkboxes name="id" options=$customers selected=$cust_id separator="<br />"}
...
<label><input type="checkbox"
<label><input type="checkbox"
Jack Smith</label><br />
<label><input type="checkbox"
<label><input type="checkbox"
name="id" value="1000" />Joe Schmoe</label><br />
name="id" value="1001" checked="checked" />
name="id" value="1002" />Jane Johnson</label><br />
name="id" value="1003" />Charlie Brown</label><br />
Příklad 9: použití funkce html checkboxes
druhý údaj je implicitně dán počtem hodnot v poli. Funkce má mnoho dalších parametrů,
pomocí nichž lze ovlivňovat formátování tabulky a umístění dat. Tato funkce není příliš
vhodná pro tabulky se záhlavím a dalšími metadaty. V takovém případě jsou vhodnější
funkce foreach a section. Použití html_table ukazuje příklad 10.
4.6
Konfigurační soubory
Konfigurační soubory jsou užitečné pro správu globálních nastavení celého webu. Příkladem
můžou být barevná schémata. Řekněme, že všechny tabulky mají být zobrazeny jednotným
stylem. Bez konfiguračních souborů by každá změna znamenala úpravy mnoha šablon a nebo
předávání barev z php, což však odporuje principu oddělení vzhledu od aplikační logiky.
Jiným příkladem, o kterém jsme mluvili již dříve, jsou jazykové mutace (viz. příklad 2).
Hodnoty v konfiguračním souboru mohou být umístěny v uvozovkách, ale není to nutné.
Pouze pokud je hodnota proměnné zapsaná přes více řádků, je nutné ohraničit ji trojnásobnými uvozovkami. Cokoliv, co odporuje syntaxi, je považováno za komentář. Při psaní
komentářů je však vhodné používat vhodnou formu, například začínat každý řádek komentáře znakem #.
Data v souboru mohou být rozdělena do sekcí. Proměnné, které nejsou součástí žadné
sekce, jsou globální. Při zavedení konfiguračního souboru se specifikovanou sekcí se do šablony
dostanou proměnné z příslušné sekce společně se všemi globálními proměnnými. Konfigurační
soubory se v šablonách používají pomocí interní funkce config_load.
5
Smarty a php
Systém Smarty nabízí široké pole působnosti i php programátorům. K tomu slouží objekt
Smarty, který jsme již mnohokrát zmiňovali. Je možné měnit hodnoty několika desítek pro9
$smarty->assign(’data’,array(1,2,3,4,5,6,7,8,9));
...
{html_table loop=$data}
{html_table loop=$data cols=4}
...
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>9</td></tr>
</table>
<table>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>5</td><td>6</td><td>7</td><td>8</td></tr>
<tr><td>9</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
</table>
Příklad 10: použití funkce html table
měnných a využívat velké množství metod. Za pozornost stojí i filtry, které lze definovat
a používat při zobrazování šablon. A pak jsou tady samozřejmě uživatelské funkce, jejichž
tvorba může usnadnit práci návrháři šablon.
Všechna tato témata jsou však pokročilejšího charakteru a (jak napovídá praxe) jejich
použití je výrazně méně časté. Proto se jim v tomto textu nebudeme dále věnovat.
6
Poznámky závěrem
Zdrojem informací pro tuto práci byla dokumentace systému Smarty a mé bohaté zkušenosti s
ním, které zahrnují bankovní aplikaci, web jednoho univerzitního projektu, bakalářskou práci
či stránky taneční skupiny. Je vidět, že šablonovací systém lze uplatnit skutečně kdekoliv.
Tento text slouží jako vysvětlení principů šablonovacích systémů reprezentativní ukázka
možností jednoho z nich. Zdaleka nejde o úplný popis. Vynechal jsem řadu funkcí dostupných
při tvoření šablon a jen lehce jsem zmínil bohaté možnosti pro php programátory. Případní
zájemci najdou všechny potřebné informace v dokumentaci.
Vše o Smarty lze najít na adrese http://smarty.php.net/.
10