Bevezető / Template rendszerek
Bevezető:
A logouton található néhány webes, PHP-s témájú írás, de olyan, melyekben a PHP-ben való webfejlesztéshez használható hasznos függvénykönyvtárakat, osztályokat, illetve minden egyéb szükséges és opcionális fejlesztőeszközt mutatnak be még nincsen. Ezért gondoltam, hogy elkezdek egy ilyen sorozatot. A cikkben nem fogok kitérni a PHP alapjaira és példakódok sokasága is vár majd a következő oldalakon, ezért a kezdőknek nem ajánlom.
Jómagam jelenleg PHP fejlesztőként dolgozok. Először kb. 4 éve kerültem kapcsolatba a nyelvvel, mikor is egy munka kapcsán felkértek egy oldal elkészítésére. A fejlesztés folyamán ismerkedtem meg a nyelvvel, később, egyetemi tanulmányaim során végighallgattam a Webtechnológiák című tárgyat és ma már szinte minden nap foglalkozok vele és használom. Úgy döntöttem, hogy ezen formában bemutatom azokat az eszközöket amit használom és leírom tapasztalataimat, hogyan célszerű, illetve én hogyan szoktam felépíteni egy oldalt. Éppen ezért, ha valami helytelen vagy pontatlan, kérem a segítségetek kijavítani, nem pedig megkövezni engem.
Ebben a cikkben a következőket találod meg:
- Mik a sablon rendszerek?
- Mi a különbség ezek és a Smarty között?
- Hogyan kell használni a Smarty Template-t?
- Hogyan építhető fel vele egy oldal logikusan?
- Tapasztalatok, ötletek, linkek
Sablon rendszerek létrejöttének okai:
- Átláthatatlanná válik a programkód, nehezen lehet elkülöníteni a megjelenéstől
- A munka ezáltal egymás után zajlik, nem egyszerre, a programozó vár a grafikusra.
- A megrendelő módosít a megjelenésen és az alkalmazás logikán is módosítani kell, ilyenkor ki vár kire?
- A megrendelő bővíteni szeretné az alkalmazást
- Ezen okokból következik, hogy függetlenné kell tenni a megjelenítést a PHP programtól
A sablon rendszerek tehát olyan eszközök, amik segítik a fenti pontok kiküszöbölését, melyekből a következő előnyök származnak:
- a grafikus és a programozó párhuzamosan tudnak dolgozni
- több rétegű alkalmazások (MVC modell)
- tisztább felépítés, az összetartozó részek egy helyen vannak
- biztonság: a grafikus nem fér hozzá a PHP kódhoz, ezáltal se szándékosan, se véletlenül nem tudja elrontani az alkalmazás logikát, illetve nem láthatja az adatbázis jelszavakat, az adatbázis szerkezetet és egyéb kritikus biztonsági tényezőket.
- gyors felületcsere: többnyelvűség
Sablon rendszerek általános jellemzői:
- Alapvető változó behelyettesítések
- Dinamikus blokk funkciók: pl. táblázat kiírása egy tömbből
- Minden oldal letöltésekor megtörténik a sablon értelmezése
- Sebesség növelés: a kész behelyettesített sablon cachelése
A Smarty Template
Smarty Template általános jellemzői:
- PHP nyelven íródott, tulajdonképpen egy PHP osztály.
- Nincs felesleges sablon értelmezés, csak az első lekérdezéskor fordul le.
- Bővíthető saját funkciókkal, módosítókkal
- Szekciók (if, foreach, section) végtelen egymásba ágyazhatósága
- A tagelválasztók átdefiniálhatóak ( { }, <{ }>, <smarty: > )
- Beépített cache rendszer: egy PHP fájlt készít, amit még értelmez a PHP és ennek az eredményét látjuk más sablonrendszerekkel szemben, ahol egy statikus html oldal készül sablonértelmezéskor.
- Saját cache funkciók is beilleszthetőek
- Többféle sablonforrás (file, db)
- Plugin rendszer
- Hatékony
- Egyszerű szintakszis, a grafikusnak könnyebb a dolga, könnyen megtanulható.
Nézzünk is egy példát rögtön, még mielőtt a sok felsorolástól elmenne a kedvetek. Legyen ez a szokásos "Hello World!" példa, egy egyszerű szövegkiíratás:
Hello Smarty példaprogram:
HelloSmarty.php:
<?php
Include_once("Smarty.class.php");
$smarty = new Smarty();
$smarty->assign("title", "Hello Smarty!");
$smarty->display("HelloSmarty.tpl");
?>
HelloSmarty.tpl:
<html><head></head>
<body>
{$title}
</body>
</html>
HelloSmarty.php futási eredménye:
<html><head></head>
<body>
Hello Smarty!
</body>
</html>
Alapértelmezett beállítás szerint a smarty a templates mappában keresi a sablon fájlokat amik kiterjesztését .tpl-re ajánlott választani, de lehet bármi más is. A futtatáshoz továbbá szükséges egy templates_c mappát is létrehozni, ugyanis ide kerülnek majd a sablonból gyártott php fájlok. Továbbá figyelni kell arra, hogy a webszerver írhassa az utóbbi mappát, különben nem tudja legenerálni a php-t.
A Smarty Template lehetőségei
{$title} vs. <?=$title?>:
Mitől is jobb a {$title} mint az egyszerű PHP-s kiíratás? A programozó lényegében belepakolja a kiírandó adatokat egy objektumba, ami aztán behelyettesíti a sablon fájlba azokat. Ebből még nem derül ki a smarty haszna, ezért nézzük meg a grafikus lehetőségeit példakód formájában:
A grafikus alap lehetőségei:
A sablonon belül a szoveg változónak adunk értéket, ezáltal a {$szoveg} ugyanúgy használható mintha az a PHP kódból tettük volna meg:
{assign var="szoveg" value="Logout"}
A változó módosítókkal megváltoztathatjuk a kiírandó szöveget. Ilyen módosítók például az összes karaktereket nagybetűssé alakító, vagy a karakterek közé egy szóközt beszúró. Ezeket a módosítókat egy "|" karakterrel fűzhetjük a változónév után, és láncolhatjuk is őket:
{$szoveg|upper} => LOGOUT
{$szoveg|spacify} => L o g o u t
{$szoveg|upper|spacify} => L O G O U T
Tömbök és objektumok
A smartyban elérhetjük a tömbök adatait is, amik akár lehetnek többször egymásba ágyazottak is. Erre használhatjuk a hagyományos "[ ]" vagy a smarty-s megoldást is ".".
{$tomb.altomb.altombkulcs}
{$tomb[altomb][altombkulcs]}
{$tomb[0][1]}
Hasonló képpen működnek az objektumok is:
{$obj->adattag}
{$obj->metodus()}
Vezérlési szerkezetek:
Léteznek azonban vezérlési szerkezetek is a smarty-ben, mint például a ciklus és a feltétel.
Nézzünk egy példát a feltételre, köszönjünk a felhasználónak. A $username változót a PHP-ból kapjuk.
{if $username eq "admin"} Hello Admin!
{elseif $username ne ""} Hello User!
{else} Hello Guest!
{/if}
A feltétel megadásánák használhatjuk a == != > < ... operátorokat is.
A következőkben nézzünk meg egy lehetséges példát a felhasználók neveinek kilistázására egy html listában (<ul> <li>). A $felhasznalonevek tömböt a PHP kódból kapja a smarty.
<ul>
{foreach from=$felhasznalonevek item=nev}
<li>{$nev}</li>
{/foreach}
</ul>
Ez a példa kezdésnek jó, de nem éppen megfelelő, ugyanis ha üres a PHP-ból kapott tömb, akkor egy üres (<ul> </ul>) html listát kapunk. Ez önmagában nem baj, de ebből következik egy probléma: a felhasználó nem kap értesítést, hogy miért nincs kiírva semmi. Könnyen kezelhető a probléma a {foreachelse} lehetőséggel:
<ul>
{foreach from=$felhasznalonevek item=nev}
<li>{$nev}</li>
{foreachelse}
A felhasználó nevek listája üres.
{/foreach}
</ul>
Ezzel már kapunk információt, hogy miért üres a lista, de most meg a szöveg az <ul> tageken belül van. Erre adnak megoldást a smarty beépített ciklus változói. Használatukhoz nevet kell adni a ciklusnak egy name attribútum segítségével (ennek az értéke legyen most ciklus). A következő ciklusváltozók léteznek:
$smarty.foreach.ciklus.first - akkor igaz ha az első elem ciklusában vagyunk
$smarty.foreach.ciklus.last - akkor igaz ha az utolsó elem ciklusában vagyunk
$smarty.foreach.ciklus.index - a ciklus indexe, sorszáma 0-tól kezdve.
Na akkor kombózzuk össze ezt egy már jónak mondható, bár első látásra nem egyszerű kódba:
{foreach from=$felhasznalonevek item=nev name=ciklus}
{if $smarty.foreach.ciklus.first}
<ul>
{/if}
<li>{$nev}</li>
{if $smarty.foreach.ciklus.last}
</ul>
{/if}
{foreachelse}
A felhasználó nevek listája üres.
{/foreach}
Itt egy másik példa arra ha a kiírandó szövegeket egy vízszintes vonallal szeretnénk elválasztani úgy, hogy az első előtt és az utolsó után ne legyen. Használjuk erre a PHP-ből kapott cikklista tömböt, és írassuk ki egymás után vonallal elválasztva a cikkek bevezetőjét.
{foreach from=$cikklista item=cikk name=ciklus}
{if !$smarty.foreach.ciklus.first}
<hr/>
{/if}
{$cikk.bevezeto}
{/foreach}
A programozó lehetőségei:
A programozó a Smarty alapszolgáltatásain kívül írhat hozzá plugineket. Ezeknek három csoportja van: a funkciók, a módosítók és a szűrők. Ez utóbbi további három részre bontható: fordítás előtti-, fordítás utáni- és kimeneti szűrők léteznek. A szűrőket használat előtt be kell tölteni. Előszűrő lehet egy html megjegyzéseket eltávolító szűrő, utószűrő lehet, az amikor egy bizonyos részt mindig be akarunk illeszteni egy oldalba. Kimeneti szűrőre jó példa az email címek védelme az adathalászat ellen, a kukac karakter helyére mást illeszt be.
További lehetőségek, gyakorlati példák
Html táblázat egyszerűen:
A következő tömböket adjuk át a smartynak, amiket majd a sablon felhasznál:
$data=array(1,2,3,4,5,6,7,8,9)
$tr=array('bgcolor="#eeeeee"','bgcolor="#dddddd");
Alapértelmezett táblázat:
{html_table loop=$data}
eredménye:
<table border="1">
<tbody>
<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>
</tbody>
</table>
Az alapértelmezett táblázatban nincs címsor és a tömb adatait 3 oszlopos formába lebontva jeleníti meg. Ha nem megfelelő az oszlopszám a cols attribútummal változtathatjuk meg. Ha további attribútumokat akarunk átadni a <table> tagnek akkor azt a table_attr attribútummal tehetjük meg. Egy keret nélküli 4 oszlopos táblázatot a következő képpen írhatunk ki:
{html_table loop=$data cols=4 table_attr='border="0"'}
eredménye:
<table border="0">
<tbody>
<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> </td><td> </td><td> </td></tr>
</tbody>
</table>
Ha szeretnénk címsor megadni akkor a cols attribútumban egy vesszővel elválasztott listában adhatjuk meg a címsor elemeit. Ha a táblázat sorainak akarunk megadni akkor a tr_attr attribútumnak kell értéket adnunk. Ha ez egy tömb, mint ebben a példában, akkor a táblázat kiíratásánál végig iterálunk ezen a tömbön. A példában tehát minden 2. sor ugyanolyan színű lesz:
{html_table loop=$data cols="first,second,third,fourth" tr_attr=$tr}
eredménye:
<table border="1">
<thead>
<tr>
<th>first</th><th>second</th><th>third</th><th>fourth</th>
</tr>
</thead>
<tbody>
<tr bgcolor="#eeeeee"><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr bgcolor="#dddddd"><td>5</td><td>6</td><td>7</td><td>8</td></tr>
<tr bgcolor="#eeeeee"><td>9</td><td> </td><td> </td><td> </td></tr>
</tbody>
</table>
Dátum és időpont választó menü:
A smartyban lehetőségünk van egy-egy paranccsal dátum és időpont választó legördülő menüket készíteni.
{html_select_date}
eredménye:
<select name="Date_Month">
<option value="1">January</option>
...
<option value="5" selected="selected">May</option>
...
<option value="12">December</option>
</select>
<select name="Date_Day">
<option value="1">01</option>
...
<option value="28" selected="selected">28</option>
...
<option value="31">31</option>
</select>
<select name="Date_Year">
<option value="2009" selected="selected">2009</option>
</select>
Alapértelmezés szerint mindig az aktuális dátumra áll a menü, de ezt természetesen módosíthatjuk további attribútumok megadásával. Attribútumokkal megadható a menü formátuma (azaz a legördülő menük sorrendje), a hónapokat magyarosíthatjuk, kezdő és záró évet adhatunk meg. A {html_select_time} paranccsal és annak attribútumaival hasonlóképpen jeleníthetjük meg az idő választót.
Gyakran használt html elem még a választó lista. Ezt a {html_options} paranccsal készíthetjük el. Paraméterként meg kell adni neki a szövegeket tartalmazó tömböt, amik meg fognak jelenni a listában. Ilyenkor az értékeket 0-tól kezdve sorszámozza. Paraméterben azonban megadható az értékeket tartalmazó tömb is. Ezt már nem részletezném, további infót a manual-ban találsz róla.
{ }:
Végül egy apró, de annál hasznosabb parancs, illetve parancsok a {ldelim} és {rdelim}. Mivel a smartyban foglalt a { és } karakter ezért gondban lennénk a javascript függvények és a stílusok írásánál. Ezt a két karaktert tehát a fenti két paranccsal írathatjuk ki:
function teszt() {ldelim}
alert('teszt');
{rdelim}
eredménye:
function teszt() {
alert('teszt');
}
+1 ráadás tipp:
Nincs annál idegesítőbb, amikor kitöltesz egy 15-20 mezőből álló formot, de a feldolgozó hibát talál benne, és amit bele írtál kitörli (pontosabban nem írja vissza). Erre tökéletes megoldás a smarty lefoglalt változói, melyek többnyire a PHP super global változóival egyenlőek.
{$smarty.get.page} ugyanaz, mint $_GET['page']
{$smarty.post.page} ugyanaz, mint $_POST['page']
{$smarty.server.SERVER_NAME} ugyanaz, mint $_SERVER['SERVER_NAME']
Ha egy formot építünk fel akkor a mezők értékének mindig adjuk meg a postos változó értékeket, ezáltal, ha hibát talál a feldolgozó visszaíródik az adat:
<form ...>
<input type="text" name="nev" value="{$smarty.post.nev}" />
...
</form>
Biztonsági okokból a smarty új verziója már csak olvasni tudja ezeket a változókat.
Egy kis megjegyzés:
Ha a sablonba akarunk megjegyzést írni megtehetjük azt html megjegyzéssel és smarty megjegyzéssel is. A kettő között a formátumon kívül még az a különbség, hogy a html megjegyzés bekerül a kimenetbe, a smarty meg nem:
<!-- html megjegyzes -->
szöveg
{* smarty megjegyzés *}
eredmény:
<!-- html megjegyzes -->
szöveg
Egy oldal felépítése / végszó
Nézzük meg a továbbiakban, hogyan lehet egy a smartyval egyszerűen felépíteni egy weblapot. Legyen a egy 3 részes (felső banner, oldalsó menü és középső terület) szerkezetű oldal a példa, ahol a középső rész cserélődik a menü hatására.
A html kód:
<html>
<head>
<title>cim</title>
</head>
<body>
<table width="100%">
<tr>
<td colspan="2">banner</td>
</tr>
<tr>
<td width="20%">menü</td>
<td>középső rész</td>
</tr>
</table>
</body>
</html>
A smarty-t használva a középső részt külön fájlokba téve egyszerűen cserélgethetjük:
<td>
...ez a középső rész...
{include file=$kozepso_resz}
</td>
Ezzel behívjuk azt a fájlt középre, aminek a fájlneve (elérési úttal együtt) a $kozepso_resz változóban van, ezt a PHP vezérlésben állítsuk be, nézzük is megy hogyan. Index.php:
<?php
//inicializálás: osztályok (smarty) betöltése, db kapcsolat indítása,...
$smarty = new smarty();
$smarty->template_dir="";
$smarty->compile_dir="smarty_php";
$site="fooldal"; // ha nincs kiválasztva semmi menü ez jelenik meg
if (isset($_GET['page'])) {
if ($_GET['page']=="menu1") {
//Menüpont tartalmának előkészítése:
$smarty->assign("adat","blablabla");
$site="menu1hez_tartozo_sablonfajl";
}
if ($_POST['page']=="form1") {
form1t_feldolgozasat_vegzo_fuggveny();
}
}
$smarty->assign("kozepso_resz",$site.".tpl");
$smarty->display("index.tpl");
?>
A sablonok a smarty_php mappába generálódnak, maguk a sablonfájlok pedig az index.php mellé kerülnek (lásd a smarty konfig részében), azért hogy az "álomtakáccsal" dolgozó grafikus kollégák, hacsak részben is, de meg tudják úgy nyitni szerkesztésre a sablonfájlokat, hogy a képek, és egyéb fájlokat is tudja kezelni a webszerkesztő program.
Nagyon hasznosnak ítélem a smarty-t, és ma már a szinte legegyszerűbb dinamikus weblapnál is ezt használom.
Egy kis példa a smarty hasznosságára: Nemrég volt egy melóm, ahol egy olyan weblapot kellett rendbe tennem, amit már kb. másfél éve toldozott-foldozott több programozó is. Függvények több helyen definiálva, a php fájlok mérete kb 5MB; php, html összevissza keveredve. Az első nap még röhögtem magamba, illetve a kollégákkal a kódon, hogy milyen gányolások voltak benne, de utána már nem volt olyan vicces. Három héttel később a kód 80kb-ra csökkent, a sablonfájlokkal és az oldal összes képével együtt nem érte az 1 MB-t az összméret.
És hogy miért is érte meg ez a munka, azon kívül, hogy minden úgy működött, ahogy kellett? 1-2 hónappal később kellett egy ugyanolyan szerkezetű, de más designnel rendelkező weboldalt készíteni ugyanannak a megrendelőnek. A grafikus kollégák munkáján kívül (~3 óra) kb. 5 óra alatt már a tárhelyen volt a weblap :D
Ha tetszett az írásom, és lesz időm a következők bemutatására gondoltam még:
- Webfejlesztő programok
- Ajax, 1-2 hasznos PHP függvénykönyvtár, JavaScript függvénykönyvtár
- PHP keretrendszerek
- Hasznos algoritmusok weboldalak felépítéséhez