Template Engines con PHP - Teoria e pratica nell'uso dei template per lo sviluppo della presentazione nelle applicazioni web-oriented
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
Template Engines con PHP Teoria e pratica nell'uso dei template per lo sviluppo della presentazione nelle applicazioni web-oriented a cura di Gabriele Lana Pag. 1
Di che cosa parliamo? Separazione fra logica e presentazione: Il mito del riuso del software Una soluzione: Il pattern MVC I template (concetti base) La computazione nei template I template (concetti avanzati) I template e le tecnologie rivali: valutazioni e commenti Un esempio completo Pag. 2
Separazione fra logica e presentazione Iniziamo con alcune definizioni: Logica: La logica di funzionamento di un sistema (business logic), è il processo di generazione e manipolazione dell'informazione Informazione: Tutto ciò che produce variazione nel patrimonio conoscitivo di un soggetto. Presentazione: Strumento cognitivo atto a rendere fruibile l'informazione ad un soggetto Vedremo quali sono le caratteristiche della logica e della presentazione, quali sono le dipendenze fra questi due aspetti di un sistema, e come queste influenzano lo sviluppo di un buona implementazione del sistema stesso Pag. 3
Logica Vs Presentazione Logica: La business logic deriva dall'analisi funzionale del sistema La valutazione di correttezza di una business procedure è obiettiva e deterministica Le business rule sono piuttosto stabili nel tempo, e qualora non dovessero esserlo si può prevedere in anticipo quali sono i punti critici Due routine che implementano la stessa business procedure sono ridondanti Presentazione: L'analisi funzionale del sistema da solo un idea di come deve essere la presentazione La valutazione di correttezza della presentazione è soggettiva e non è deterministica La valutazione soggettiva di una presentazione non è stabile nel tempo (i gusti possono cambiare), e non è possibile prevederlo in anticipo Due presentazioni diverse della stessa informazione possono portare grande beneficio (adattività, usabilità, accessibilità, ...) Pag. 4
Il mito del riuso del software Abbiamo detto che logica e presentazione sono concetti ortogonali, ma non è del tutto vero, in realtà hanno entrambi una dipendenza verso l'informazione, la logica produce l'informazione che deve essere resa fruibile dalla presentazione LOGICA Da ai dati una struttura Produce INFORMAZIONE Rende fruibile PRESENTAZIONE Da ai dati una descrizione Per minimizzare lo sforzo d'implementazione del sistema, spesso si è tentati di utilizzare direttamente l'informazione prodotta dalla logica durante la creazione della presentazione, creando una fortissima dipendenza fra le due Pag. 5
Un esempio Pag. 6
Il mito del riuso del software Quali sono i rischi che si corrono? Per ogni presentazione diversa ci deve essere un identica elaborazione dell'informazione (ridondanza, entropia) Una modifica alla presentazione potrebbe, accidentalmente o volontariamente, produrre delle modifiche all'elaborazione dell'informazione (refactoring non ristrutturante, devolution) Scarsa leggibilità del codice, difficoltà nella documentazione dello stesso Tutto questo si traduce in uno scarsa probabilità di riuso del software con tutti gli svantaggi che questo comporta. Pag. 7
Una soluzione: Il pattern MVC (Model, View, Control) Secondo il pattern MVC, il sistema può essere considerato come un insieme di componenti collaboranti, ognuna di queste costituita da tre entità Model: Mantiene le informazioni e la logica di Model funzionamento della componente View: Rappresenta la strategia di visualizzazione (rappresentazione) del modello Control: Mappa gli eventi sollevati attraverso la vista (eventi utente) in eventi significativi per il modello (eventi di sistema) View Control Pag. 8
La view nelle applicazioni web Scopo di questo talk è quello di presentare l'utilizzo dei template come strumento implementativo delle View all'interno di un'architettura modellata secondo il pattern MVC con lo scopo di disaccoppiare la logica (Model) dalla presentazione (View). La View in ambito web è costituita da un testo contenente: Idati della componente, richiesti dall'utente La descrizione dei dati fatta attraverso un opportuno linguaggio Facciamo un esempio di due presentazioni diverse degli stessi dati: Ciao Gabriele Lana sei il visitatore numero 10 Gabriele Lana 10 Pag. 9
I template I template sono modelli di View che vengono creati a partire da due linguaggi di descrizione: Linguaggio di struttura: Linguaggio di descrizione della struttura dei dati Linguaggio di presentazione: Linguaggio di descrizione della presentazione dei dati I template dell'esempio di prima apparirebbero così: Ciao #$NOME_UTENTE# sei il visitatore numero #$NUMERO_VISITATORE# #$NOME_UTENTE# #$NUMERO_VISITATORE# Pag. 10
Come funzionano? In risposta ad una richiesta fatta da un utente viene chiamata in causa una componente del sistema, il Control della componente mappa la richiesta dell'utente in un metodo del Model, il quale produce (o elabora) dei dati strutturati. Il Control recupera i dati dal Model, crea un'istanza del Template Engine passandogli il nome del file contenente il template ed infine passa i dati al Template Engine che penserà a fare il merge fra la dichiarazione della struttura dei dati contenuta nel template e i dati veri e propri. Template Ciao #$NOME# Output Template Ciao PHP-DAY Data Engine ... $data['NOME'] = 'PHP-DAY'; ... Pag. 11
Fondamenti di grammatica: Un esempio Template (esempio_1.tpl) : #$TITLE# #$TITLE# Dati dell'utente #$USER#: Nome: #$USER['FIRSTNAME']# Cognome: #$USER['SURNAME']# Data di nascita: #$USER['BORNDATE']# Tel: #$USER['TELNUMBER']# Hobbies: #$USER['HOBBIES']# Pag. 12
Fondamenti di grammatica: Un esempio Codice PHP (esempio_1.php) : Strutturazione dei dati 'Gabriele', 'SURNAME' => 'Lana', 'BORNDATE' => '2/7/1977', 'TELNUMBER' => '340/3494782', 'HOBBIES' => 'Computer, Cinema, Palestra' ); // Uniamo i dati ricavati agli altri dati del template $data = array( 'TITLE' => 'Visualizzazione dati utente', 'USER' => $userInfo['FIRSTNAME'].' '.$userInfo['SURNAME'], 'UserInfo' => array( 'USER' => $userInfo)); ?> Pag. 13
Fondamenti di grammatica: Un esempio Codice PHP (esempio_1.php ) : Merge dei dati con il template attraverso il TE
Fondamenti di grammatica: Un esempio Output: Visualizzazione dati utente Visualizzazione dati utente Dati dell'utente Gabriele Lana: Nome: Gabriele Cognome: Lana Data di nascita: 2/7/1977 Tel: 340/3494782 Hobbies: Computer, Cinema, Palestra Pag. 15
Fondamenti di grammatica: Variabili ed Espressioni Variable ::= $NOME_VAR [ \[SELETTORE\] ] Durante l'interpretazione del template ogni ricorrenza di una variabile viene sostituita con il suo valore Una variabile non necessita di essere dichiarata Ad una variabile può essere assegnato qualsiasi tipo di valore valido per il PHP Il valore sostituito ad una variabile viene considerato di tipo stringa dal LS, per questo le variabili vengono definite come elementi produttori di stringa In Line Element ::= Variable | String | Value Modifier Expression ::= # \| InLineElement [ \| InLineElement \| ... ] \| # Per ora ci limitiamo ad espressioni che contengono solo variabili Pag. 16
Fondamenti di grammatica: Blocchi statici Static Block Open ::= Static Block Close ::= Identifica una regione strutturalmente significativa del template Un blocco può contenere ogni elemento del linguaggio di struttura Grazie ai blocchi il modello dei dati del LS può definirsi gerarchico Ogni blocco ha un nome ed identifica un namespace Ogni elemento ha un nome unico all'interno del template che chiameremo nome assoluto. Il nome assoluto di un elemento viene costruito concatenando il nome assoluto del blocco che contiene l'elemento con il nome dell'elemento stesso (ex. Il blocco UserInfo ha come nome assoluto /Main/UserInfo, la variabile USER contenuta in questo blocco ha come nome assoluto /Main/UserInfo/USER, che è una variabile diversa rispetto a /Main/USER) Il contenuto di un blocco viene considerato dal LS di tipo stringa, per questo anche i blocchi vengono definiti come elementi produttori di stringa Pag. 17
Fusione fra dati e template Matching: Il match fra i dati e il modello definito dal LS all'interno del template viene fatto per nome, attraverso l'uso di array viene creato uno spazio dei nomi simile a quello definito dai blocchi all'interno del template. Agli elementi del template vengono assegnati i dati degli array corrispondenti array(3) { ["TITLE"]=> ... ... ["USER"]=> ... #$TITLE# ["UserInfo"]=> #$USER# array(1) { ... ["USER"]=> array(5) { ... ... #$USER# } ... } } ... Pag. 18
Fondamenti di grammatica: Blocchi dinamici Per i dati di un solo utente il template che abbiamo costruito va bene, ma se volessimo fare il display dei dati di più utenti? Possiamo pensare di modificare il template enumerando tutti gli utenti (esempio_2.tpl) : ... Dati dell'utente #`$USER[0]['FIRSTNAME']` `$USER[0]['SURNAME']`#: Nome: #$USER[0]['FIRSTNAME']# Cognome: #$USER[0]['SURNAME']# Data di nascita: #$USER[0]['BORNDATE']# Tel: #$USER[0]['TELNUMBER']# Hobbies: #$USER[0]['HOBBIES']# Dati dell'utente #`$USER[1]['FIRSTNAME']` `$USER[1]['SURNAME']`#: Nome: #$USER[1]['FIRSTNAME']# ... ... ... Pag. 19
Fondamenti di grammatica: Blocchi dinamici Strutturando i dati nel modo seguente (esempio_2.php) : $usersInfo = array( 0 => array( 'FIRSTNAME' => 'Gabriele', 'SURNAME' => 'Lana', 'BORNDATE' => '2/7/1977', 'TELNUMBER' => '340/3494782', 'HOBBIES' => 'Fumetti, Cinema, Palestra'), 1 => array( 'FIRSTNAME' => 'Giovanni', ... ), ); Possiamo ottenere lo scopo, ma questa soluzione è problematica: Il codice è prolisso, noioso da scrivere e poco manutenibile Non è applicabile nei casi in cui il numero degli utenti non è conosciuto a priori Per queste ragioni introduciamo i blocchi dinamici Pag. 20
Fondamenti di grammatica: Un esempio Template (esempio_3.tpl) : #$TITLE# #$TITLE# Dati dell'utente #`$USER['FIRSTNAME']` `$USER['SURNAME']`#: Nome: #$USER['FIRSTNAME']# Cognome: #$USER['SURNAME']# Data di nascita: #$USER['BORNDATE']# Tel: #$USER['TELNUMBER']# Hobbies: #$USER['HOBBIES']# Pag. 21
Fondamenti di grammatica: Un esempio Codice PHP (esempio_3.php) : Strutturazione dei dati
Fondamenti di grammatica: Un esempio Output: ... Visualizzazione dati utenti Dati dell'utente Gabriele Lana : Nome: Gabriele ... Dati dell'utente Giovanni Rossi : Nome: Giovanni ... Dati dell'utente Mario Verdi : Nome: Mario ... Pag. 23
Fondamenti di grammatica: Blocchi dinamici Dynamic Block Open ::= Dynamic Block Close ::= Sono identici agli array statici, l'unica differenza è che il loro contenuto può essere ripetuto un numero indefinito di volte. Quando viene assegnato un array ad un blocco dinamico, gli elementi dell'array devono essere a loro volta array, per ognuno di questi il contenuto del blocco dinamico verrà replicato creando un blocco statico al quale verrà assegnato il contenuto dell'array con le regole che abbiamo visto. La concatenazione di tutti i blocchi statici creati rappresenta l'output del blocco dinamico Array(3) { Blocco dinamico [“0”] => array(1) { // Dati prima ist. } [“1”] => array(1) { // Dati seconda ist. Istanze } Blocco dinamico [“2”] => array(1) { // Dati terza ist. } Pag. 24
Fondamenti di grammatica: Blocchi dinamici Per dimostrare la praticità dei blocchi statici, supponiamo di avere in una tabella di un RDBMS gli stessi dati che abbiamo dell'esempio precedente, e vediamo come riuscire ad ottenere lo stesso array e quindi lo stesso risultato. La tabella è così definita: CREATE TABLE USER_INFO ( USERID INT AUTO_INCREMENT PRIMARY KEY NOT NULL, FIRSTNAME CHAR(50), SURNAME CHAR(50), BORNDATE CHAR(50), TELNUMBER CHAR(50), HOBBIES CHAR(50) ); Il codice da utilizzare è il seguente (esempio_4.php) : // Creazione dell'array da assegnare al blocco Main $data = array('TITLE' => 'Visualizzazione dati utenti'); // Recupero dei dati sugli utenti $result = mysql_query('SELECT * FROM USER_INFO', $link); while ($row = mysql_fetch_assoc($result)) $data['UsersInfo'][]['USER'] = $row; Pag. 25
La computazione nei template Supponiamo di avere molti utenti e di voler impaginare i loro dati all'interno di una tabella descritta usando l'html. Modifichiamo il template (solo quello) per il nostro scopo (esempio_4.tpl) : ... #$TITLE# Nome: #$USER['FIRSTNAME']# Cognome: #$USER['SURNAME']# Data di nascita: #$USER['BORNDATE']# ... Pag. 26
La computazione nei template Scopriamo che il risultato è poco leggibile. Una soluzione molto comune è quella di dare una colorazione di sfondo alternata per ogni riga, ma come è possibile ottenere questo? I blocchi dinamici per definizione sono collezioni di tipi di dati identici, quindi risulta impossibile farlo a meno di intervenire direttamente modificando i dati attraverso codice PHP. Questo violerebbe la separazione della logica dalla presentazione, non è detto infatti che un'altra vista non usi questi colori (l'esempio numero 3 e 4 ne è una prova), i dati devono essere validi per tutte le viste. Introduciamo a questo proposito dei nuovi elementi nel LS che, anche se in maniera dichiarativa, riescono a produrre la computazione necessaria affinchè il LS sia in grado di manipolare la presentazione in base non solo alla struttura dei dati, ma anche al valore degli stessi Pag. 27
La computazione nei template: Value Modifier Modifichiamo il template precedente (esempio_4.tpl) nel seguente modo (esempio_6.tpl) : ... #$TITLE# Nome: #$USER['FIRSTNAME']# Cognome: #$USER['SURNAME']# Data di nascita: #$USER['BORNDATE']# ... Pag. 28
La computazione nei template: Value Modifier I dati restano immutati, ma serve la definizione del ValueModifier (esempio_6.php) : Value Modifiers ::= ValueModifierName : [ Param : ... ] Rientrano all'interno della categoria degli inline elements e per questo sono utilizzabili solo all'interno delle expression Sono delle funzioni in grado di ricevere parametri in ingresso, e di fornire un risultato in uscita. I parametri in ingresso vengono identificati in maniera posizionale, il primo parametro sarà memorizzato in $params[0], il secondo in $params[1], ecc... Nell'esempio viene utilizzata una variabile speciale ($BLOCK_COUNT), essa viene impostata automaticamente dal blocco dinamico e conta il numero dell'istanza attuale Pag. 29
La computazione nei template: Value Modifier Il risultato è il seguente: Nome: Gabriele Cognome: Lana Data di nascita: 2/7/77 Tel: 340/3494782 Hobbies: Fumetti, Cinema, Palestra Nome: Giovanni Cognome: Rossi Data di nascita: 14/3/1980 Tel: 555/4456456 Hobbies: Calcio, Nuoto, Tennis Nome: Mario Cognome: Verdi Data di nascita: 23/8/1974 Tel: 555/3223888 Hobbies: Viaggi, Arte e artigianato ... Pag. 30
La computazione nei template: String Modifier Supponiamo ora di voler fare il display delle ultime news inserite all'interno di una tabella del nostro DB. La tabella è del tipo (create_table_esempio_7) : CREATE TABLE NEWS ( ID INT AUTO_INCREMENT NOT NULL PRIMARY KEY, TITLE VARCHAR(100), USER_POST VARCHAR(100), TIME_POST CHAR(50), BODY TEXT ); Vogliamo in un caso fare il display di un incipit delle news, e in un altro caso vogliamo fare il display dell'intera news. Nel primo caso non dobbiamo visualizzare tutti i dati della news e dobbiamo troncare il corpo della stessa. Nel secondo caso dobbiamo visualizzare tutti i dati. Attraverso l'uso degli string modifier è possibile ottenere entrambi i risultati scegliendo solo il template adatto. Pag. 31
La computazione nei template: String Modifier Il template che useremo nel primo caso (esempio_7_1.tpl) #$TITLE# #$TITLE# #$NEWS['TITLE']#: #$NEWS['BODY']# Prosegue Pag. 32
La computazione nei template: String Modifier String Modifier ::= Sono elementi del linguaggio che possono essere applicati ad altri elementi del linguaggio, in particolare ad elementi produttori di stringa. Sono in grado di modificare la stringa prodotta dall'elemento al quale sono applicati Sono anch'essi elementi produttori di stringa, quindi sono applicabili in serie Come i value modifier sono funzioni definibili dall'utente, in questo modo fungono da meccanismo di estensione del LS Il prototipo della funzione è il seguente: function EvaSModTruncate(&$vars, &$content) { // $vars contiene tutti gli attributi dichiarati // $content contiene la stringa che deve essere modificata ... // Ritorna la stringa modificata return $content; } Pag. 33
La computazione nei template: String Modifier Screenshot dell'output nel primo caso: Pag. 34
La computazione nei template: String Modifier Il template che useremo nel secondo caso (esempio_7_2.tpl) ... Uso di fogli di stile per l'impaginazione #$TITLE# #$NEWS['TITLE']# #$NEWS['BODY']# Posted by:#$NEWS['USER_POST']#, at:#$NEWS['TIME_POST']# Pag. 35
La computazione nei template: String Modifier Screenshot dell'output nel secondo caso: Pag. 36
Template Vs ADT ADT (Abstract Data Type) Dati strutturati + Operazioni La struttura viene definita Le operazioni vengono definite dal dal linguaggio di struttura template engine Utilizzando questo parallelo è possibile notare che esistono due forti carenze espressive nel linguaggio di struttura, ovvero non è possibile definire strutture polimorfiche, ne è possibile definire strutture ricorsive. Polimorfismo: Deriva dal greco e significa letteralmente “molte forme”, ci riferiamo qui alla possibilità di poter dichiarare delle collezioni (attraverso dynamic block) di tipi non omogenei. Abbiamo visto, con l'esempio relativo ai value modifier, come è possibile interpretare i dati (dello stesso tipo) e darne una corretta visualizzazione, ma noi vogliamo di più. Pag. 37
Template Vs ADT: Polimorfismo Sarebbe opportuno poter gestire collezioni di dati non omogenei che necessitano di visualizzazioni non omogenee la cui scelta si basa proprio sul tipo di dato. Un esempio è quello del menu, il quale è composto da una collezione di due tipi di entità: i folder e i link. Diremo che entrambi possono essere definiti come item del menu. Possiamo schematizzare nel seguente modo: Da questo diagramma UML si evince che un Folder è un Item, Item un Link è un Item, e i Folder possono contenere item, i quali possono essere sia Folder che Link (polimorfismo) Folder Link Pag. 38
Template Vs ADT: Ricorsione Ricorsione: La possibilità di creare strutture dati ricorsive è fondamentale, sopratutto se si vogliono trattare linguaggi di presentazione come l'XML che sono per natura ricorsivi (descrivendo un modello di dati gerarchico). Un esempio di struttura ricorsiva ci è fornito proprio dal menu. Il menu può essere definito come un elenco di item, gli item possono essere definiti come elementi astrazione di elementi concreti quali i link e i folder. Il link è un elemento del menu che permette di collegare il menu con una risorsa esterna. Il folder è un elenco di item, ma essendo un item definito attraverso la nozione di link e folder, abbiamo che il folder per essere definito usa la sua stessa definizione creando una struttura ricorsiva. ... Un possibile XML di descrizione di un menu ... ... ... ... Pag. 39
Template Vs ADT: Un esempio Come è possibile modellare un menu in XML con i template? E' possibile introducendo un nuovo elemento del LS, i Recursive Block, e aggiungendo il concetto di Selezione. Vediamo il template dell'esempio completo (esempio_9.tpl) : #$ITEM['TITLE']# #$ITEM['URL']# ... Pag. 40
Template Vs ADT: Un esempio (polimorfismo) Di seguito viene mostrato il contenuto del blocco dinamico che deve contenere tutti gli items del menu stesso (esempio_9.tpl) : #$ITEM['TITLE']# #$ITEM['URL']# #$ITEM['IMAGE']# Due elementi che hanno lo stesso nome (Item), cosa succede quando viene assegnato un valore all'elemento Main/Folder/Content[i]/Item? A tale elemento sarà assegnato (per assunzione) una struttura dati contenente l'elemento $ITEM['TYPE'], se il valore di tale elemento sarà uguale alla stringa “Folder”, i dati saranno assegnati al primo elemento, se sarà uguale alla stringa “Link”, al secondo, altrimenti a nessuno. Pag. 41
Template Vs ADT: Un esempio (ricorsione) Cosa succede invece assegnando un valore ad un blocco ricorsivo? (esempio_9.tpl) : ... ... L'assegnamento ad un blocco ricorsivo implica una modifica nella struttura del template stesso. Un blocco ricorsivo si “riferisce” ad un altro blocco all'interno del template. Durante l'assegnamento, il blocco riferito (e tutto il suo contenuto) viene sostituito al blocco referente (il blocco ricorsivo), alla fine i dati vengono assegnati al nuovo blocco. E' da notare se il blocco ricorsivo è contenuto nel blocco riferito (come nel nostro caso), la copia conterrà tale blocco consentendo una nuova trasformazione. Pag. 42
Template Vs ADT: Un esempio Vediamo i dati che possono essere assegnati al template (esempio_9.php) : $data = array( 'Folder' => array( 'ITEM' => array( ... ), Primo livello 'Content' => array( '1' => array( F 'Item' => array( 'ITEM' => array( 'TYPE' => 'Link', ... ))), '2' => array( 'Item' => array( Secondo livello 'ITEM' => array( L F L 'TYPE' => 'Folder', ... ), 'Content' => array( '1' => array( 'Item' => array( 'ITEM' => array( 'TYPE' => 'Link', Terzo livello ... )))))), L '3' => array( 'Item' => array( 'ITEM' => array( 'TYPE' => 'Link', ... )))))); Pag. 43
Template Vs ADT: Un esempio Vediamo il risultato dell'assegnamento : Primo livello ... ... F ... ... ... Secondo livello L F L ... ... ... Terzo livello ... ... L ... Pag. 44
Template Vs XSLT L'XSLT (eXtensible Style Language Transformation) è un'applicazione XML atta a definire trasformazioni su altri XML ben formati. Vediamo uno schema di funzionamento: Foglio di stile XSLT Output Processore XSL Gabriele Lana Giovanni Mario Sorgente dati XML Pag. 45
Template Vs XSLT L'output della trasformazione precedente: Gabriele Lana Giovanni Verdi Mario Rossi I template che abbiamo visto risolvono le stesse problematiche delle trasformazioni XSLT, vediamo un confronto delle loro caratteristiche: I template permettono di utilizzare molte diverse sorgenti di dati (DBMS, XML, LDAP, flat-file, ...), l'XSLT necessita un XML ben formato come fonte di dati. Ovviamente è sempre possibile recuperare i dati da una sorgente, generare l'XML sorgente di dati e quindi effettuare la trasformazione, ma l'overhead va sempre considerato I template sono generalmente più performanti (dipende dall'implementazione) anche se ultimamente ci sono progetti rivolti alla precompilazione dei fogli di stile Pag. 46
Template Vs XSLT Le trasformazioni XSLT consentono facilmente di operare trasformazioni successive (ammesso che l'output sia un XML ben formato), i template lo consentono ma non altrettanto facilmente La limitazione più grande delle trasformazioni XSLT è che sono poco intuitive. Nonostante la loro natura dichiarativa (sono applicazioni XML) sono fortemente orientate alla computazione, non sono solo definizioni (come il LS nei template), ma sono definizioni che comportano azioni. Questo non permette la separazione dei compiti in un team di sviluppo, cosa invece favorita dai template. Attraverso i template è possibile per un web designer creare un modello della pagina anche utilizzando strumenti WYSIWYG (appositamente configurati) Pag. 47
Bibliografia e Riferimenti ADT: 'Programming with abstract data types' Ulrich Berger 'Specification of ADT' J.Loeckx, H.D. Ehrich Teoria sui template: 'A type system for dynamic web documents' Anders Sandholm Template engine PHP: Smarty (http://smarty.php.net) SmartTemplate (http://www.smartphp.net) Ets (http://ets.sourceforge.net) Template engine Python: Empy (http://www.alcyone.com/pyos/empy) Cheetah (http://www.cheetahtemplate.org) Template engine Java: Velocity (http://jakarta.apache.org/velocity) FreeMarker (http://freemarker.org/index.html) Pag. 48
Bibliografia e Riferimenti MVC: 'Design Patterns: Elements of Reusable Object-Oriented Software' Gof Il pattern secondo sun ( http://java.sun.com/blueprints/patterns/MVC-detailed.html) Una risorsa generale sui pattern ( http://hillside.net/patterns/patterns.htm) Rappresentazione di strutture ricorsive su RDBMS: 'Joe Celko's SQL for Smarties: Advanced SQL Programming' Joe Celko XSLT: Riferiemento ufficiale del W3C (http://www.w3.org/TR/xslt) 'XSLT' Doug Tidwell 'XSLT Cookbook' Sal Mangano Pag. 49
Puoi anche leggere