Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Il template engine per Taste: introduzione

Scegliere un template engine per Taste: cosa sono i template engine e quali sono le principali tendenze nella loro implementazione
Scegliere un template engine per Taste: cosa sono i template engine e quali sono le principali tendenze nella loro implementazione
Link copiato negli appunti

Nell'articolo precedente abbiamo concluso la parte di articoli relativa al core all'architettura necessaria per implementare ed utilizzare i Controller. Con questo articolo ci lasceremo da parte (dandoli per acquisiti) i concetti descritti precedentemente ed inizieremo a trattare argomenti riguardanti le viste ed in senso più stretto lo studio e l'implementazione di un Template Engine.

Il Template Engine che implementeremo si baserà su una struttura molto semplice, forse non adatta per carichi di lavoro eccessivi a meno che non gli si affianchi un buon sistema di caching. L'obiettivo comunque, come sempre, non è quello di strutturare ed implementare un ottimo template engine, ma quello di cercare di descrivere, con l'ausilio di un po' di codice, il processo di design e scrittura di un sistema simile.

Le diverse tipologie di template engine

Agli albori della programmazione web (ed anche tuttora in alcuni progetti, purtroppo) era abitudine dei programmatori sviluppare le proprie applicazioni web aggiungendo direttamente il codice PHP al codice HTML. Questa procedura risultava molto comoda, soprattutto per chi proveniva dallo sviluppo CGI e si trovava ora ad avere una flessibilità molto più alta rispetto a prima.

Con il tempo, purtroppo o fortunatamente, ci si rese conto che il sistema utilizzato rendeva il codice difficile da mantenere e soprattutto creava seri problemi di interazione con tutti quei designer che non avevano intenzione di studiare PHP per poter successivamente intervenire per risolvere eventuali imperfezioni grafiche.

Una delle soluzioni introdotte per questo problema furono appunto i Template Engine che permettevano una netta separazione tra logica e presentazione, adattandosi oltretutto perfettamente al modello MVC che si stava pian piano affermando.

Esistono decine di implementazioni di template engine, alcune sviluppate a livello amatoriale, altre che possono essere tranquillamente utilizzate anche a livello enterprise. Possiamo comunque raggruppare i template engine in tre grossi gruppi, differenziati dalla tipologia di sintassi utilizzata per integrare la template ai dati prodotti dalla logica di programmazione:

  • Template basati su codice PHP: questa tipologia di template sfrutta la possibilità di scrivere codice PHP inline all'interno del codice HTML limitando le istruzioni grazie alla sintassi alternativa degli statement PHP, cosa che permette di utilizzare delle keyword per delimitare il corpo di uno statement senza dover utilizzare delle parentesi graffe. Questo approccio deriva da quello introdotto da Ruby on Rails, che utilizza direttamente Ruby come linguaggio di Template. Nonostante siano interessanti, i template engine implementati in questo modo sono difficilmente controllabili al 100% dal programmatore che dovrebbe limitare il codice nocivo inseribile nei template e risultano spesso poco chiari;
  • Template XML: questa seconda tipologia di template utilizza come linguaggio di base XML corredato da una serie di namespaces e tag particolari che permettono di controllare il rendering finale del template. Alcuni template engine utilizzano soltanto gli attributi per controllare il rendering, mentre altri template usano direttamente i tag;
  • Template testuali: l'ultima tipologia di template utilizza una sintassi proprietaria testuale, spesso molto simile a quella di un linguaggio di programmazione tradizionale oppure simile all'XML. Il vantaggio di questo tipo di template engine rispetto a quelli in XML è che sono in grado di generare anche codice non XML, quindi possono essere utilizzati in altri contesti come la creazione dinamica di file di configurazione o file di risorse.

Ogni tipologia di template engine ha i suoi grandi vantaggi ed anche i suoi grandi svantaggi. Scegliere quale implementare o utilizzare è sempre un compito arduo, che si basa molto sul gusto personale e sul progetto per il quale si dovrà implementare il sistema.

Il template engine di Taste

Per Taste ho deciso di implementare un template engine basato su XML. La scelta è dovuta ad alcuni fattori:

  • L'implementazione di un template engine testuale è un processo che richiede molto codice di supporto, soprattutto per il parsing e lo scanning dei sorgenti. Utilizzando XML come base ci si può basare sulle implementazioni native di DOM e SAX, con il risultato di riuscire ad ottenere buoni risultati con poco lavoro;
  • Usare XML come base permette un semplice check sulla sintassi ed una linearità di codice che rende facilmente leggibile le template;
  • XML è un linguaggio conosciuto dai designer e la maggior parte di loro lavora generando codice XHTML;
  • I template engine basati su PHP richiedono molto codice aggiuntivo al fine di generare un sistema che permetta di limitare i danni apportabili da chi scrive i template, limitando allo stretto necessario il codice interpretabile;
  • Gusto personale;

Svilupperemo il codice in modo abbastanza lineare, senza addentrarci in alcune problematiche (come la compilazione in codice nativo, che oltretutto è spesso difficile da ottenere con template XML come quello che andremo ad implementare) che esulano dal contesto. Nonostante ciò comunque raggiungeremo un buon livello di utilità e completezza della libreria grazie all'implementazione di un sistema di plug-in ed a una struttura di codice che permetterà di utilizzare sia tag che attributi per il controllo del flusso di rendering.

La struttura del codice

Come accennato poche righe fa, non è molto ampio il codice necessario per implementare un template engine che basa il suo linguaggio su XML e che sfrutta DOM per il parsing. È comunque fondamentale strutturare correttamente la proprie classi fin dall'inizio, al fine di riuscire ad ottenere un sistema modulare funzionante e facilmente estendibile.

Il modulo per la gestione dei template XML è organizzato in cinque classi principali, che ora introdurremo e di cui discuteremo l'implementazione nel prossimo articolo.

La classe più semplice è TemplateException, che serve per l'appunto come eccezione base da lanciare nel caso il template engine generi degli errori durante la sua esecuzione.

L'intero flusso di operazioni è gestito dalla classe Template: ad un'istanza di questa classe possiamo associare una serie di proprietà che verranno poi utilizzate durante la fase di esecuzione per la generazione dell'output. Durante il processo di renderizzazione viene navigato ricorsivamente l'intero albero DOM generato dal sorgenti XML assegnato: quando le routine di navigazione incontrano un namespace che corrisponde all'ID di un plug-in registrato, attivano questo plug-in ed eseguono i comandi corrispondenti agli eventuali tag o attributi che incontreranno a cui sarà stato associato quel determinato namespace.

Ogni plug-in è definito come una classe che estende TemplatePlugin (il plugin di default è definito nella classe DefaultTemplateEngine e viene installato automaticamente a runtime) ed espone una serie di metodi che eseguono operazioni su nodi DOM. È compito del metodo stesso modificare di conseguenza l'albero ed eventualmente procedere con la navigazione dei suoi figli al fine di applicare le informazioni necessarie. Per recuperare il valore di un parametro dinamico che può essere assegnato a runtime all'oggetto Template, i plug-in interrogano istanze dell'oggetto Scope. L'oggetto Scope rappresenta lo scope del flusso di codice che si sta eseguendo in un determinato momento: lo scope può essere incrementato o decrementato al fine di rispondere alle esigenze specifiche dei comandi di un plug-in.

Il plug-in di default che implementeremo esporrà, sotto forma di attributi, alcune delle funzionalità più comuni implementate nei template basati su XML:

  • content: sostituisce il contenuto di un nodo con il valore della variabile passata come valore dell'attributo e recuperata dallo scope corrente;
  • replace: sostituisce il nodo con il valore della variabile passata come valore dell'attributo e recuperata dallo scope corrente;
  • omit: rimuove il nodo dall'output;
  •  condition: visualizza il nodo solamente se la variabile passata come argomento ha un valore vero;
  • repeat: ripete il contenuto del nodo per ogni elemento contenuto nell'array passato come argomento;

Conclusione

Abbiamo terminato l'introduzione e la descrizione di come andremo ad implementare il template engine. Ho deciso di utilizzare un approccio abbastanza semplice ma potente, al fine di permettere a chiunque di estendere le funzionalità del modulo in modo che si adattino alle esigenze della propria applicazione. In futuro è anche possibile che descriva come estendere il sistema in modo che supporti la compilazione in codice PHP o il caching parziale dell'output, ma per ora preferisco limitarmi a questo.

Ti consigliamo anche