PDA

Pogčedajte punu verziju : Mala Template klasa


Ilija Studen
04. 06. 2006., 17:53
Nije template jezik već jednostavna klasa koja izoluje template od ostatka aplikacije i omogućava lako baratanje sa njima. Daklen:

<?php

include 'Template.class.php';

tpl_assign('firstname', 'Ilija');
tpl_assign('lastname', 'Studen');
tpl_display('templates/something.php');

?>

A something.php izgleda:

<?php if($firstname && $lastname) { ?>
<p>Dobrodosao <?= $firstname ?> <?= $lastname ?></p>
<?php } else { ?>
<p>Ne znam tvoje ime i prezime :(</p>
<?php } ?>

Pored display() koji printuje kod ima i fetch() metod koji otvara output buffer, poziva display i vraća sadržaj output buffera nakon što je template pozvan (tj. vraća šta god je template printao kao string). Tu je i assign_by_ref funkcija.

I... to je to :) Skoro godinu dana radim sa ovom klasom i nije mi se ukazala potreba za bilo čim složenijim. Maleno, jednostavno, radi posao i ne smeta.

<?php

/**
* Template class
*
* This class is template wrapper, responsible for forwarding variables to the
* templates and including them.
*
* @version 1.0
* @author Ilija Studen <ilija.studen@gmail.com>
*/
class Template {

/**
* Array of template variables
*
* @var array
*/
var $vars = array();

/**
* Assign variable value to the template
*
* @access public
* @param string $name Variable name
* @param mixed $value Variable value
* @return boolean
*/
function assign($name, $value) {
if(trim($name) == '') return false;
$this->vars[trim($name)] = $value;
return true;
} // assign

/**
* Assign value by reference
*
* @access public
* @param string $name
* @param mixed $value
* @return boolean
*/
function assignByRef($name, &$value) {
if(trim($name) == '') return false;
$this->vars[trim($name)] = $value;
return true;
} // assignByRef

/**
* Display template and retur output as string
*
* @access public
* @param string $template Absolute path template path
* @return string
*/
function fetch($template) {
ob_start();
$display = $this->display($template);
if($display === false) {
ob_end_clean();
return false;
} // if
return ob_get_clean();
} // fetch

/**
* Display template
*
* @access public
* @param string $template Template path or path relative to templates dir
* @return boolean
*/
function display($template) {
return $this->includeTemplate($template);
} // display

/**
* Include specific template
*
* @access public
* @param string $template Absolute template path
* @return null
*/
function includeTemplate($template) {
if(file_exists($template)) {
foreach($this->vars as $k => $v) {
if(!isset($$k)) $$k = $v;
} // foreach

include $template;
return true;
} else {
return false;
} // if
} // includeTemplate

/**
* Return template service instance
*
* @access public
* @param void
* @return Template
*/
function &instance() {
static $instance;
if(!is_object($instance) || !is_a($instance, 'Template')) {
$instance = new Template();
} // if
return $instance;
} // instance

} // Template

// ================================================== ============
// Shortcut methods
// ================================================== ============

/**
* Assign template variable
*
* @access public
* @param string $varname Variable name
* @return boolean
*/
function tpl_assign($varname, $varvalue) {
$template_engine =& Template::instance();
return $template_engine->assign($varname, $varvalue);
} // tpl_assign

/**
* Assign variable by reference
*
* @access public
* @param string $varname
* @param mixed $varvalue
* @return boolean
*/
function tpl_assign_by_ref($varname, &$varvalue) {
$template_engine =& Template::instance();
return $template_engine->assignByRef($varname, $varvalue);
} // tpl_assign_by_ref

/**
* Render template and return it as string
*
* @access public
* @param string $template Template that need to be rendered
* @return string
*/
function tpl_fetch($template) {
$template_engine =& Template::instance();
return $template_engine->fetch($template);
} // tpl_fetch

/**
* Render specific template
*
* @access public
* @param string $template Template that need to be rendered
* @return boolean
*/
function tpl_display($template) {
$template_engine =& Template::instance();
return $template_engine->display($template);
} // tpl_display

?>

robi-bobi
04. 06. 2006., 20:04
cenim tudje iskustvo (koje moze biti drugacije od mojeg)
cenim to sto cesto citam od tebe dobre postove
cenim to sto si postovao svoj kod na download

ali kakav je smisao takvog template-a?
da konkretizujem pitanje:
sta konkretno dobijas ovom klasom?

ako se vec tezi laganom resenju, zasto ne otici korak dalje i uopste ne koristiti template

P.S. ne kazem da ne treba odvajati logiku od prezentacije (to je nesto sasvim drugo)

MorenoArdohain
04. 06. 2006., 20:20
Meni je zatrebao neki ultralaki template sistem, posto u Smarty-ju koristim skoro samo foreach, literal, if/else, count i include, pa cu u dogledno vreme osakatiti njegov engine..
Ilijina klasa resava stvar za neke sitnije projekte, ali za vece stvari ipak je dobro koristiti template engine..

Ilija Studen
04. 06. 2006., 20:20
ali kakav je smisao takvog template-a?
da konkretizujem pitanje:
sta konkretno dobijas ovom klasom?

Sličan pristup odvajanja aplikacije od prezentacionog dela kao kod Smartyja samo minimalizovan. Teško da može manje od ovoga, a osnovna funkcionalnost je zadržana (ne zagađuje se scope aplikacije, sve je izolovano, a zadržana je kompletna fleksibilnost templatea jer se mogu koristiti sve mogućnosti PHPa kao jezika).

Šta podrazumevaš pod "otici korak dalje i uopste ne koristiti template"? Primer takvog načina pošto ja stvarno ne vidim ništa loše u korišćenju templatea.

BraMom
04. 06. 2006., 20:30
Dobra ideja, php i jeste preprocessor, a i lepo kodiranje.

Šta bih tu rado video:

1. Ruzna je ova sintaksa tipa "<?php } else { ?>", kad bi se u templejtu to mozda pisalo kao {else}, a da klasa generise ovakav fajl (koji je kod tebe templejt) i snima ga u neki direktorijum, npr. templates_c/

2. Pa jos neki plugin, za <select> tag (html_options) i slicno...

I dobiješ smarty light... Ali onda se odstupa od osnovne ideje, a i već imamo smarty.

Čekaću da "otvoriš" php code generator, pretpostavljam da će me više zainteresovati.

Ilija Studen
04. 06. 2006., 20:46
1. Ruzna je ova sintaksa tipa "<?php } else { ?>", kad bi se u templejtu to mozda pisalo kao {else}, a da klasa generise ovakav fajl (koji je kod tebe templejt) i snima ga u neki direktorijum, npr. templates_c/

Jeste ružna. To je ujedno i jedina veća mana jer se mnogima neće svideti. Mada, opet preporučujem korišćenje nekog ozbiljnijeg PHP editora i nema problema. Zend Studio ne pravi nikakve probleme sa blokovima, jasno ih razaznaje iako je između otvaranja i zatvaranja umetnut blok HTMLa, radi code completion (od čega možeš da se oprostiš kod Smartyja) itd. Kad se jednom navikneš ista stvar kao bilo koji drugi template jezik...

Što se tiče dodataka za brzo generisanje select boxova i slično to ubacujem u template spolja. Nije deo ove klase (helper koncept pozajmljen or Railsa).

Petar Marić
05. 06. 2006., 10:46
Heh, tvoji template fajlovi me maksimalno podsećaju na JSP ;)

ivanhoe
05. 06. 2006., 11:40
pa dobro, JSP je jedna od lepsih stvari u vezi jave IMHO :D

Edit: Evo sad sam tek stigao da bacim pazljivije pogled na kod, i imam par sitnih zamerki :

if(trim($name) == '') return false;
$this->vars[trim($name)] = $value;

ovo se pojavljuje na vise mesta u kodu. U najvecem broju slucajeva ce parametar biti ok, pa ces da imas dupliran poziv trim() funkcije. Efikasnije bi bilo da se pise :
if( ! $trimmed = trim($name) )
return false;
$this->vars[$trimmed] = $value;

Dalje:
foreach($this->vars as $k => $v) {
if(!isset($$k)) $$k = $v;
} // foreach

nema potrebe da se tako radi, postoji php funkcija extract() koja radi istu stvar, samo mnogo efikasnije..

Takodje mislim da je dizajn same klase mogao da bude jos jednostavniji, malkice je previse rasparcan kod, imas puno metoda koje su prakticno obicni wrapperi za druge metode.. Ako je ideja da dalje usloznjavas mogucnosti klase onda ok, a ako je ideja da je koristis ovakvu kakva je, sa naglaskom na brzini i efikasnosti, onda bi mogao da izbegnes posrednike, posto su pozivi metoda najsporiji deo koda (mislim bas na kod, ne na pozive ka spoljnim resursima tipa baze i fajlova, naravno)

robi-bobi
05. 06. 2006., 17:37
mislio sam na ovako nesto
t.j. cist plain PHP


<?php
$firstname = 'Ilija';
$lastname = 'Studen';

include ('templates/something.php');
?>


<?php if($firstname && $lastname) { ?>
<p>Dobrodosao <?= $firstname ?> <?= $lastname ?></p>
<?php } else { ?>
<p>Ne znam tvoje ime i prezime :(</p>
<?php } ?>

Sad, vidim da radis trim, ovo-ono, ali meni mozda treba taj novi red na kraju promenljive
Takodje radis neke return false i slicno, medjutim ne vidim da igde proveravas sta je vraceno ;)


pošto ja stvarno ne vidim ništa loše u korišćenju templatea
sve je stvar navike i stila
ne kazem da je loshe, pitam sta realno dobijas ovim - iskreno me interesuje

Ilija Studen
05. 06. 2006., 18:42
Hvala za komentare. Ima ovde što-šta da se nauči. Šta bi tek bilo da sam postovao neko složenije parče koda :D

@Ivanhoe

1. 100% si u pravu, ne sećam se kad sam zadnji put uneo pogrešno ime promeljive. Ta provera se može tretirati suvišnom, ali ipak nek ostane. Samo ponavljanje treba saseći.
2. Tek sad čujem za extract(). extract($this->vars, EXTR_SKIP) radi isti posao.
3. Jedino što može da se uradi, a da se izbegne copy paste je da se unutar fetch() metoda koristi includeTemplate() direktno (jer display u stvari radi samo to).

@Robi-Bobi - problem sa tvojim pristupom je što promenljive koje koristiš u templateime moraju da budu u istom scopeu gde se vrši include templatea. U većini slučajeva možeš da namestiš takvu situaciju, ali je to po meni nepraktično. Recimo samo da znam bar jedan pristup gde je takav pristup kamen oko vrata (da sad ne opisujem kako i šta, može da potraje). Ovako jednostavno sve template promenljive uguraš u scope za koji si 100% siguran da će biti dostupan templateima i to je to.

Ne trimuje se vrednost promenljive već njeno ime. Whitespace ionako ne možeš da imaš u imenu promenljive.

Što se vraćanja vrednosti tiče ova klasa baca exceptione u originalnom obliku, ali pošto toga u PHP4 nema samo zamenio sa return false. Ko voli nek proverava ;)

robi-bobi
06. 06. 2006., 23:19
da, sa tim sam saglasan
scope zna biti problem i to ti priznajem :)

Bojan Zivanovic
11. 06. 2006., 17:37
Meni je zatrebao neki ultralaki template sistem, posto u Smarty-ju koristim skoro samo foreach, literal, if/else, count i include, pa cu u dogledno vreme osakatiti njegov engine..
Ilijina klasa resava stvar za neke sitnije projekte, ali za vece stvari ipak je dobro koristiti template engine..
Jel si probao Template Lite (http://templatelite.sf.net)?
To je fork engina koji se zvao Smarty Lite (promenili ime kada je Smarty trademarkovao svoje ime) Na prvi pogled ima sve ono osnovno sto i inace koristim kod Smarty-ja, tako da cu ga verovatno probati u sledecem projektu...