phemplate tutorialas

2002.02.24 užrašė pukomuko


įvadas
pagrindai
ciklai / loops
blokai
praktiniai pavyzdžiai
dvigubas ciklas / nested loop
forma
lentelė su duomenimis horizontaliai
išvadas

įvadas

jei nesi naudojęs ar net girdėjęs apie templeitus - nesinervink :) aš pats ilgai dirbau įprastu būdu ir vargo nemačiau. bet kuo gudresnis skriptas, tuo labiau pasimeta kodas tarp html'o. pats html sugalvotojas yra pasakęs, kad html'as nebuvo skirtas skaityti žmonėms, tai mašinų kalba. tad php sąvybė, kad jis gali būti rašomas į html vidurius, yra ir labai patogi greituose skriptuose, bet tuo pačiu labai bjauri, kai prireikia padaryti kažką didesnio arba pasidalyti darbą.

ką siūlo templeitų sprendimas? visiškai atskirti php kodą nuo html. tada galima ramiai atiduoti skritpo išvaizdą žmogui, kuris atsakingas už html, ir nebijoti, kad viskas pasibaigs labai blogai. dažniausiai taikant templeitus kodas pasidaro žymiai aiškesnis, bet bandant padaryt tai, ko templeitų varikliukas tiesiogiai nepalaiko, tenka ir pasispjaudyti :]

čia pabandysiu papasakoti, kaip naudoti templeitų varikliuką phemplate. kodėl būtent šį? todėl, kad aš jį parašiau ir tai vienintelis, kurį aš naudoju intensyviai bei suprantu iš vidaus. phemplate puslapis - naujausios žinios ir šviežiausia versija.

visus šio tutorialo pavyzdukus galima atsisiųsti čia. beje, virš pavyzdukų esantys failų vardai yra linkai į veikiančius skriptus.

pagrindai

kas yra templeitas arba šablonas? tai tiesiog html arba kitoks tekstinis failas, kuriame sutartais ženklais pažymėtos vietos, kuriose reiks įterpti duomenis iš skripto. priklausomai nuo varikliuko yra palaikomi ir papildomi navarotai :]

pagrinde phemplate operuoja teksto gabalėliais, kurie turi vardus/handle. ir failai, ir kintamieji, ir blokai, apie kuriuos paaiškinsiu vėliau, turi vienodą prioritetą, yra tame pačiame namespace (guli toje pačioje saugykloje). todėl funkcijos set_var() ir set_file() praktiškai daro tą patį - suteikia turinį nurodytam handlui. vienintelis kitokį statusą turintis dalykas yra ciklai/loopai.

kaip naudoti phemplate varikliuką? štai elementariausias pavyzdukas, kuris nedaro nieko, o tik išveda nurodyto failo turinį:
1.plain.php / 1.plain.html
<? 
include('phemplate.class.php');

$tpl = new phemplate();

$tpl->set_file('text', '1.plain.html');
echo $tpl->process('', 'text');
?>
čia pavyzdukas, kaip templeite pakeičiamas kintamasis:
<? 
include('phemplate.class.php');

$tpl = new phemplate();

$tpl->set_var('data', date('Y.m.d'));

$tpl->set_file('text', '2.set_date.html');
echo $tpl->process('', 'text');
?>
 
šios dienos data - {data}
taigi pakartoju tiksliau: metodas set_var($handle, $var) priskiria handlui $handle, kintamojo $var turinį, o metodas set_file($handle, $file_name) priskiria handlui $handle, failo $file_name turinį.
metodas process($dest, $source) atlieka parsinimo veiksmą: ieško $source handlo turinyje pažymėjimų {vardas} ir jei randa keičia juos į handlo vardu 'vardas' turinį, toks perparsintas tekstas dedamas į $dest handlą, jei toks jau egzistuoja, tai turinys užrašomas ant viršaus. metodas gražina naują handlo $dest turinį.

vienas navarotas: jei metodui set_var($handle, $var), vietoje $var paduosi ne stringą, o masyvą, tai bus sukurta tiek handlų kiek masyve elementų, o jų vardai bus konstruojami pagal tokią schemą:
<? 
include('phemplate.class.php');

$tpl = new phemplate();

$variable = array (
	'id' => 3,
	'info' => 'foo foo',
	'sub' => array (
		'id' => 5,
		'info' => 'sub info'
	)
);

$tpl->set_var('var', $variable);

$tpl->set_file('text', '3.array.html');

echo $tpl->process('', 'text');
?>
 
masyvo elementų vardai pridedami
per tašką prie handlo vardo:
<br>
<br>
var.id - {var.id}<br>
var.info - {var.info}<br>
var.sub.id - {var.sub.id}<br>
var.sub.info - {var.sub.info}<br>
<br>
atkreipiu dėmesį, kad tokio handlo 
kaip <b>var</b> neatsirado.

ciklai / loops

visas web programavimas dažniausiai susiveda į du dalykus: duomenų redagavimo formas ir duomenų iš db sąrašus. pastarajam palengvinti ir yra sumastyti loop'ai phempleite. loop'as - tiesiog tam tikros struktūros masyvas (array), kuris registruojamas metodu set_loop(). kodėl būtent tokia struktūra? todėl, kad pasiimti selecto rezultatą iš db aš naudoju tokią funkciją:
db funkcija
<? 
	function get_result()
	{
		while ($row = mysql_fetch_array())
		{
			$res[] = $row;
		}
		return $res;
	}
?>
todėl gaunasi būtent tokios struktūros masyvas:
loop.inc
<? 
$loop = array(
	0 => array(
		'id' => 1,
		'info' => 'blahaha'
	),

	1 => array(
		'id' => 4,
		'info' => 'blahaha antra eilute'
	),

	2 => array(
		'id' => 12,
		'info' => 'blahaha trecia eilute'
	)
);

/*
turiu uomenyje, kad masyvas sudarytas iš masyvų, 
kurie sunumeruoti skaičiais nuo 0 
(taip įvyksta automatiškai jei nenurodinėt indeksų).
o visi vidiniai masyviai yra vienodos sandaros
*/
?>
vat tokį masyvą galima regsitruoti metodu set_loop($loop_handle, $loop). galima bandyt registruot ir kitokios struktūros masyvus, bet veikimas neprognozuojamas. šis metodas sukuria templeite $loop kopiją. galbūt pamiršau pasakyt, bet set_var() irgi kuria duomenų kopijas, todėl duomenis reikia registruoti, kai su jais jau atliktos visos reikalingos operacijos.

templeite loop'ai žymimi specialiu tagu <loop>. tage turi būti nurodytas parametras name su loop'o handlu. būtinai mažosiomis raidėmis, ir parametras apskliaustas dvigubomis kabutėmis. parametras būtinas tiek atidarančiame tage, tiek ir uždarančiajame (ko nesupranta frontpage:). kad loopai veiktų reikia nurodyti papildomą parametrą metode process('dest', 'source', 1), šis vienetukas nurodo, kad reikia surasti ir įvykdyti loop tagus. loop'o vidinio masyvo elementai žymimi taip {loop_handle.element_name}. štai mažas pavyzdukas kuris atspausdina visą $loop turinį:
<? 
include('phemplate.class.php');
include('loop.inc'); // duomenys

$tpl = new phemplate();

$tpl->set_loop('handle', $loop);

$tpl->set_file('text', '4.loop.html');

echo $tpl->process('', 'text', 1);
?>
 
taipogi tai ir pavyzdys 
kaip iš loop'o padaryti lentelę:
<br><br>

<table border='1'>

<loop name="handle">
<tr>
	<td>{handle.id}</td>
	<td>{handle.info}</td>
</tr>
</loop name="handle">

</table>
kas atsitinka kai masyvas tuščias? tiesiog iš html dingsta loop tagas su visu savo turiniu. jeigu tokiu atveju nori išvesti kažkokį pranešimą, reikia naudoti <noloop> tagą, kuris turi būti loop tago viduje, mažosiomis raidėmis ir su loop handlo parametru. o metodas process('dest', 'source', 2) kviečiamas su 2 vietoj vienetuko.
<? 
include('phemplate.class.php');
$tpl = new phemplate();

$tpl->set_loop('handle', array());

$tpl->set_file('text', '5.noloop.html');

echo $tpl->process('', 'text', 2);
?>
 
tuščio loop'o pavyzdys:
<br><br>

<loop name="handle">

šios teksto nematysim, jei loop'as tuščias

<noloop name="handle">
deja masyvas buvo tuščias
</noloop name="handle">
</loop name="handle">

</table>
pastaba apie greitį: set_var() galima pridaryti kiek tik nori, nes phemplate ieško tik tų handlų, kuriuos sutinka parsindamas tekstą, tuo tarpu set_loop() reiktų užregistruoti tik tiek, kiek tikrai bus tekste, nes ieškoma visų užregistruotų loop'ų.

blokai

praktiškai jau esamų featurų užtenka normaliam darbui, aš ir pats pusmetį dirbau su templeitų klase pukoplate :], kuri buvo phemplate pirmtakas ir turėjo tik aukščiau aprašytas galimybes. tačiau visas grožis pasimato tik įvaldžius blokus.

teoriškai tiek kintamasis, tiek užkrautas failas, tiek blokas yra vienas ir tas pats - teksto gabalas su vardu. skiriasi tik keliai, kaip jie užkraunami į phemplate. kintamojo turinį turi parengti pats skriptas, failas traukiamas iš disko, o blokai imami iš failų.

iškvietus metodą set_file('handle', 'filename.html', 1) su parametru 1, phemplate nurodytame faile ieškos blokų, juos iškirps iš failo turinio ir įdės į handlus, kurių vardai pažymėti bloko apraše. blokų žymėjimo sintaksė labai panaši į loop'ų: <block name="handle">bloko turinys</block name="handle">. jeigu nori žymėti bloką bloke, reikia kviesti metodą set_file('handle', 'filename.html', 2) su parametru 2, bet be ypatingo reikalo to nepatariu, nes greitis krenta :] nors jei tų blokų nedaugiau nei pirštų nemanau, kad labai pastebimai.
<? 
include('phemplate.class.php');
$tpl = new phemplate();

$tpl->set_file('text', '6.block.html', 1);

if (date('s')%2)
{
	$tpl->process('output', 'block1');
}
else
{
	$tpl->process('output', 'block2');
}

echo $tpl->process('', 'text');
?>
 
pavyzdys su blokais:
<br><br>

{output}

<block name="block1">

pirmas blokas

</block name="block1">

<block name="block2">

antras blokas

</block name="block2">

<br><br>
bandykit refresh'int

praktiniai pavyzdžiai

kartojimas mokslų motina, o programavimo motina yra praktika :] bandžiau prigalvoti, kokius gi pavyzdžius būtų tikslingiausia pateikti, bet kiek žiūriu į sourcus viskas normaliai be jokių navarotų sukodinta. tad pateikiu kelis gudresnius sprendimus, kuriuos teko sugalvoti. jeigu susiduri su kažkokia problema įgyvendindamas sprendimą - klausk, jei bus tipinė problema pridėsiu skyrelį prie tutorialo :]

dvigubas ciklas / nested loop

dažnas klausimas - kaip padaryti ciklą cikle? atsakymas labai paprastas - išorinį ciklą reikia realizuoti blokais, o vidinis normaliai loopais. vienintelis kabliukas - išoriniams blokams kviečianiant metodą process('dest', 'source', 1, 0, 1) nurodyti parametrą append - trečią skaičiuką (antrasis naudojamas pažymėt, kad reik ieškoti include file tagų, kuriais aš pats niekad nesinaudojau, ir tiesą sakant net nežinau ar tas mechanizmas veikia korektiškai).

pavyzdyje kiekvienai masyvo iš loop.inc eilutei, atspausdinsim jį patį:
<? 
include('phemplate.class.php');
include('loop.inc');

$tpl = new phemplate();

$tpl->set_file('text', '7.nestedloop.html', 1);

for($i = 0; isset($loop[$i]); $i++)
{
	$tpl->set_var('info', $loop[$i]);
	$tpl->set_var('eilute', 'eilute' . ($i+1));
	// čia reiktų loop'ą settinti priklausomai nuo $i
	$tpl->set_loop('list', $loop);

	$tpl->process('ciklas_cikle', 'ciklas', 1, 0, 1);
}

echo $tpl->process('', 'text');
?>
 
ciklo cikle pavyzdys:
<br><br>
{ciklas_cikle}

<block name="ciklas">
<b>{eilute}</b> {info.id} {info.info}
<table border='1'>

<loop name="list">
<tr>
	<td>{list.id}</td>
	<td>{list.info}</td>
</tr>
</loop name="list">

</table>
<br><br>
</block name="ciklas">

forma

einu į darbą paieškosiu sourcų, namie ištrynau kaip tais :]

lentelė su duomenimis horizontaliai

kartais turimą duomenų masyvą reikia sudėti taip:
1 2 3
4 5 6
vienas iš galimų sprendimų, deja, jei paskutinėje eilutėje trūksta informacijos, tai cellės nesukuriamos.
<? 
include('phemplate.class.php');
include('loop.inc');

$tpl = new phemplate();

$tpl->set_file('text', '9.table1.html', 1);

$cols = 2; // kiek stulpelių bus

$index = 0;

while (isset($loop[$index]))
{
	$tpl->set_var('cells', ''); // uznulinam celles
	for ($i = $index; ($i - $index < $cols) && isset($loop[$i]); $i++)
	{
		$tpl->set_var('info', $loop[$i]);
		$tpl->process('cells', 'cell', 0, 0, 1);
	}
	$index += $cols;
	$tpl->process('rows', 'row', 0, 0, 1);
}

echo $tpl->process('', 'text');
?>
 
horizontalios lentelės pavyzdys:
<br><br>

<table border=1>
{rows}
</table>

<block name="row">
<tr>
	{cells}
</tr>
</block name="row">

<block name="cell">
<td>{info.id}</td>
</block name="cell">

išvadas

tikiuosi šis tutorialas pagelbėjo įsisavinant phemplate klasę. jeigu rasit klaidų, ar sugalvosit konkrečių klausimų - būtinai pameilinkit salna@ktl.mii.lt

2002.02.25