• User

    [Guida] Template Engine Smarty

    --> Siccome sarà una cosa lunga e che mi porterà via del tempo la posto a puntate <--

    Era un pò di tempo che non mi cimentavo più con i template e sinceramente Smarty l'avevo un pò dimenticato oltre al fatto che l'ultima verisone da me utilizzata era la 2 mentre per php 5.3.x =>
    è necessario usare la 3. Per fortuna un paio di giorni fa ho dovuto riniziare ad usarlo quindi ho pensato di scrivere questa guida che non vuole assolutamente sostituirsi alla documentazione
    ufficiale, seppur in larga parte la ricalchi, ne essere una traduzione di essa anche se al momento non è disponibile la traduzione in italiano, ma semplicemente un sunto di cose da fare e
    perchè farle; una sorta di promemoria insomma rivolto sia a me stesso che notoriamente sono un distratto che la metà basta capace di perdersi gli occhiali da sole solamente perchè li ho in fronte
    (cosa successa più di una volta), sia a quanti utilizzano, vogliono utilizzare, desiderano un blocchetto pieno di appunti su questo motore di template o semplicemente sono curiosi di sapere cosa fa,
    come usarlo e come funziona.

    Buona lettura.

    ****ATTENZIONE: LEGGERE ATTENTAMENTE I COMMENTI IN TUTTI I FRAMMENTI, SPEZZONI O CODICI SORGENTI PROPOSTI IN QUESTA GUIDA IN QUANTO CONTENGONO MOLTO INFORMAZIONI
    SOTTO FORMA DI NOTE.

    NOTA: TUTTI GLI ESEMPI PROPOSTI SONO STATI PERSONALMENTE TESTATI SU WINDOWS, OSX LION E GNU/LINUX ****

    Sommario

    1. Scaricare Smarty

    2. Installare Smarty

    3. Inizializzazione rapida

    4. Inizializzazione complessa

    5. Inizializzazione mediante Singleton

    6. Inizializzazione mediante Singleton avanzato

    7. Scaricare Smarty
      Non essendo un utente premiun il forum non mi fa postare link diretti però il sito di riferimento è reperibile come primo risultato mettendo smarty nel motore di ricerca più famoso al mondo.

    8. Installare Smarty
      Una volta scaricato l'archivio compresso (al momento in cui scrivo l'ultima versione è la 3.1.11) decomprimetelo e create un nuovo progetto dentro alla webroot del vostro server apache dandogli
      la seguente struttura:

    smartyStudio (o altro nome a scelta per il progetto) e al suo interno create le cartelle cache, configs, templates e templates_c. Infine copiate le cartelle plugins e sysgplugins, contenute nella
    cartella libs del archivio compresso, e i file debug.tpl, Smarty.class.php e SmartyBC.class.php dentro alla cartella smartyStudio.

    NOTA: Smarty può essere installato e configurato in vari modi come ad esempio con dei percorsi assegnati direttamente nei file di configurazione di php (php.ini) ma poichè questo è un argomento
    estremamente avanzato che riguarda solo chi amministra dei server e poco ha a che vedere con l'applicazione anche professionale distribuita completa dei sorgenti di Smarty, cosa per altro ammessa dalla licenza, vi rimando al capitolo 2 della documentazione ufficiale. Un discorso diverso meritano i permessi sulle directory di Smarty in quanto su Windows sono del tutto ininfluenti mentre su GNU/Linux, testato personalmente anche su OSX Lion, devono essere impostati come segue:

    templates_c permessi 777, nome utente nobody, gruppo nobody
    cache permessi 777, nome utente nobody, gruppo nobody

    1. Inizializzazione rapida
      Ordunque adesso che la nostra installazione di Smarty è completa (ricordo che per installazioni avanzate rimando al capitolo 2 della documentazione ufficiale) è necessario testarla.
      Per prima cosa create due file al interno di smartyStudio chiamandoli index.php e index.tpl poi aprite index.php e immettete il seguente codice:

    [php]
    <?php

    // Includo la classe Smarty
    require_once 'Smarty.class.php';

    // Creo un'istanza della classe Smarty
    $smarty = new Smarty();

    // Assegno i percorsi alle directory di smarty
    $smarty->setTemplateDir('templates/');
    $smarty->setCompileDir('templates_c/');
    $smarty->setConfigDir('configs/');
    $smarty->setCacheDir('cache/');

    // Definisco un parametro da visualizzare (al posto di XXX metteteci il vostro nome o il nome della fidanzata o di chi volete)
    $smarty->assign('name', 'XXX');

    // Faccio il rendering del template
    $smarty->display('index.tpl');

    ?>
    [/php]

    Cosa abbiamo fatto ?

    1. Per prima cosa abbiamo incluso la classe smarty nel nostro progetto
    2. Poi ne abbiamo creto un'istanza
    3. Dopo è stato necessario richiamare i metodi per assegnare il percorso alle directory definite in precedenza e delle quali parlerò in modo esaustivo più avanti
    4. Ci siamo procurati un semplice valore da visualizzare
    5. Infine è stato richiamato il metodo display che non fa altro che passare al file index.tpl il valore della variabile name per il rendering a video.

    Nel file index.tpl inseriamo queste righe

    [php]
    {* Smarty *}
    Ciao {$name} questo è il tuo primo template generato con Smarty!. Compliemti.
    [/php]

    Se quando aprite la pagina vi appare il messaggio "Ciao XXX questo è il tuo primo template generato con Smarty!. Complimenti." avete configurato tutto bene. In merito a quanto detto sino adesso va notato che:

    1. Tutto ciò che è compreso tra {* e *} viene considerato un commento e non viene visualizzato.
    2. Smarty dispone di una console di debug interna attivabile settando a true il metodo debugging prima di richiamare il metodo display come nello snippet che segue

    [php]
    $smarty->assign('name', 'XXX');
    $smarty->deugging = true;
    $smarty->display('index.tpl');
    [/php]

    1. Scrivere $smarty->assign('name', 'XXX') e {$name} equivale a scrivere, ad esempio in php, $name = "XXX", echo $name in quanto prima abbiamo dichiarato una variabile (name) assegnandole un
      valore (XXX) e dopo abbiamo provveduto a stamparla ($name).

    2. Inizializzazione complessa
      Esiste un altro modo inizializzare ed utilizzare Smarty ed è un metodo che consente di non inizializzare continuamente le stesse varibiali, i percorsi e tutto il resto. Questo modo prevede
      l'estensione della classe originale Smarty nel seguente modo. Per prima cosa si crei un file chiamato SmartySetup.class.php al cui interno si mettano le seguenti righe:

    [php]
    <?php

    // Includo la classe Smarty
    require_once 'Smarty.class.php';

    class Smarty_smartyStudio extends Smarty
    {

    public function __construct()
    {
    
        // Eredito il costruttore originale
        parent::__construct();
    
            // Setto tutti i percorsi
            $this->setTemplateDir('templates/');
            $this->setCompileDir('templates_c/');
            $this->setConfigDir('configs');
            $this->setCacheDir('cache/');
    
            // Attivo il sistema di cache interno
            $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
    
            // Dichiaro il nome dell'applicazione
            $this->assign('app_name', 'Smarty Studio');
    
    }
    

    }
    ?>
    [/php]

    Una volta fatto questo si editi il file index1.php e si mettano al suo interno le seguenti righe:

    [php]
    <?php

    // Non viene inclusa la classe Smarty ma quella che eredita dalla stessa
    require_once 'SmartySetup.class.php';

    // Non viene inizializzata la classe Smarty ma quella che eredita
    $smarty = new Smarty_smartyStudio();

    // Il resto rimane uguale esattamente come rimane uguale il codice del file index.tpl
    $smarty->assign('name', 'XXX');
    // $smarty->debugging = true;
    $smarty->display('index1.tpl');
    ?>
    [/php]

    In ultimo si crei il file index2.tpl
    [php]
    {* Smarty *}
    Ciao {$name} questo è il tuo primo template generato con Smarty!. Compliemti.
    [/php]

    1. Inizializzazione mediante Singleton

    Un altro metodo, seppur non ufficiale, per inizializzare Smarty è farlo mediante un Design Pattern Singleton. Senza stare a scendere troppo nei dettagli il Singleton è quella struttura di
    progettazione che permette di non creare tante istanze di una classe ma averne sempre e solo una indipendentemente da quante connessioni al sito ci sono attive in un dato momento. Per valutare
    l'utilità di questa struttura si prenda ad esempio un qualsiasi CMS dove ogni volta che viene visualizzata una pagina, indipendentemente dalla locazione geografica da cui questa viene richiesta,
    lo script accede al database per recuperare alcune informazioni che possono essere di varia natura; ultimi articoli postati, articoli di pertinenza per quella data area geografica, impostazioni
    linguistiche, impostazioni personalizzate per l'utente se questi è riconosciuto dal sistema e via dicendo. Per recuperare queste informazioni lo script non fa altro che connettersi al database
    ed eseguire le query necessarie ed è appunto in questa fase che il Singleton entra in gioco in quanto se per 10 ipotetici utenti diversi lo script si dove connettere 10 volte, creando quindi
    altrettante istanze della classe preposta a tale scopo in memoria, trammite il Design Pattern Singleton ne crea una e usa sempre quella in quanto il Singleton verifica se ad ogni nuova richiesta
    c'è già un'istanza della classe e se si la utilizza indipendentemente se la richiesta avviene dal browser che ne ha richiesto la creazione o meno altrimenti la crea ex novo.

    Per creare un'istanza Singleton procediamo in questo modo:

    1. Creiamo un file di nome configure.php al cui interno metteremo un semplice controllo
    2. Creiamo una nuova classe, tipicamente un classe di utilità chiamata Factory, al interno della quale metteremo il codice necessario
    3. Creiamo il file index3.tpl
    4. Creiamo il file index3.php

    Il file configure.php contiene un namespace. Non sarebbe strettamente necessario e chiunque è libero di usare le costanti o anche delle variabili. Io lo uso semplicemente perchè spesso e
    molto volentieri nei miei progetti senza andrei in conflitto con i nomi.
    configure.php
    [php]
    <?php

    // Definiamo una namespace
    namespace FactorySmarty
    {

    // Dentro il namespace definiamo una costante per attivare o disattivare il debug di smarty
    const SMARTYDEBUG = true;
    
    // E una costante per attivare o disattivare il debug del Singleton (questa costante è utile per
    // verificare se il Disegn Pattern sta funzionando o se ogni volta viene creata una nuova istanza
    const SMARTYSINGLETON = true;
    
    // Per disattivare i controlli è sufficiente impostarle a false
    

    }
    ?>
    [/php]

    Factory.class.php
    [php]
    <?php

    // Per prima cosa includiamo la classe che abbiamo esteso in precedenza
    require_once 'SmartySetup.class.php';

    // Poi creiamo la nostra classe singleton
    class FactorySingletonSmarty
    {

    /**
     * Dichiariamo un attributo privato per verificare se esiste l'istanza
     * Per convenzione si usa la notazione ungherese
     *
     * @param bool
     * @return bool
     *
     */
    static private $_smartyInstance;
    
    /**
     *
     * Preveniamo la creazione di un costruttore e la clonazione
     *
     */
    public function __construct()
    {
    
    }
    
    public function __clone()
    {
    
    }
    
    /**
     *
     * Creiamo il Singleton come metodo statico
     *
     * @return $_SmartyInstance 
     *
     */
    static public function getInstance()
    {
    
        /**
         *
         *    Verifico se esiste l'istanza della classe
         *
         */
        if (!self::$_smartyInstance)
        {
    
            try
            {
    
                /**
                 *
                 *    Se l'istanza non esiste la creo
                 *
                 */
                self::$_smartyInstance =  new Smarty_smartyStudio();
    
            }
    
                /**
                 *
                 * Mi preparo a gestire le eccezioni.
                 * Da notare che pur quanto Smarty sia dotato di una sua gestione delle eccezioni 
                 * quello che ci stiamo accingendo a gestire non è Smarty stesso ma il Singleton
                 *
                 */
                catch(Excpetion $e)
            {
    
                    /**
                     *
                     * printException non è un metodo di Smarty ma definito da me
                     *
                     */
                    self::printException($e);
    
            }
    
        }
             return self::$_smartyInstance;
    
    }
    
    /**
     *
     *        Rapporto completo dell'errore in caso di eccezione
     *
     */
    static protected function printException($e)
    {
    
        echo '<html><head><title>Messaggio di Errore</title></head><body>';
    
            $trace = '<table border="0"><center>';
                foreach ($e->getTrace() as $file => $b) {
                    foreach ($b as $args => $d) {
                        if ($args == 'args') {
                            foreach ($d as $position => $details) {
                                $trace .= '<tr><td><b>' . strval($file) . '# </b></td><td align="right"><u>args: </u></td> <td><u>'
                              . $position . '</u> : </td><td><i>' . $details . '</i></td></tr>';
                            }        
                        } else {
                            $trace .= '<tr><td><b>' . strval($file) . '# </b></td><td align="right"><u>' . $args
                                   . '</u>:</td><td></td><td><i>' . $d . '</i></td>';
                        }
                    }
                }
                            $trace .= '</center></table>';
                            echo '<br /><br /><center><font face="Verdana"><fieldset style="width: 66%; border: 1px solid black;><legend background="black"><b>[</b>PHP PDO Error '
                                . strval($e->getCode()) . ' <b>]</b></legend><table border="0"><tr><td align="left"><b><u> Message: </u></b></td><td><i> ' . $e->getMessage()
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Code: </u></b></td><td><i> ' . strval($e->getCode())
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>File: </u></b></td><td><i> ' . $e->getFile()
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Line: </u></b></td><td><i> ' . strval($e->getLine())
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Trace: <br /></u></b></td><td><br /><br />'
                                . $trace . '<br /></td></tr></table></fieldset></center></font>';
                            echo '</body></html>';
                            die();
        
    }
    
    /**
     *
     * Se il debug è attivo vengono lanciate due istanze della classe e vengono confrontate. Se il Singleton funziona sono uguali altrimenti sono diverse
     *
     */
    static public function debug()
    {
    
        $objSmarty = self::getInstance();
        $objSmartyTest = self::getInstance();
            if ($objSmarty === $objSmartyTest)
            {
            
                echo "Ok le istanze sono uguali";
        
            } else {
            
                echo "Si è verificato un errore e le istanze non sono uguali";
        
            }
    
    }    
    

    }

    ?>
    [/php]

    Scriviamo il file index3.php

    [php]
    <?php

    // Includiamo il file con il namespace
    require_once 'configure.php';
    // Poi includiamo la classe Factory
    require_once 'Factory.class.php';

    /**
    *

    •    Un semplice controllo per verificare il Singleton
      

    */
    if (FactorySmarty\SMARTYSINGLETON == true) { FactorySingletonSmarty::debug(); }

    try
    {

    /**
     *
     *        Creo un'istanza Singleton di Smarty
     *
     */
    $objSmarty = FactorySingletonSmarty::getInstance();
    
    $objSmarty->assign('name', 'XXX');
    
    /**
     *
     * Decido se attivare o no il debug interno di smarty
     *
     */  
    if (FactorySmarty\SMARTYDEBUG == true) { $objSmarty->debugging = true; }
    
    /**
     *
     * Visualizzo il risultato
     *
     */
    $objSmarty->display('index3.tpl');
    

    }

    catch (Excpetion $e)
    

    {

    echo "Si è verificato un errore " . $e->getMessage() . "<br />";
    

    }

    ?>
    [/php]

    In ultimo il file index3.tpl
    [php]
    {* Smarty *}
    Ciao {$name} hai attivato correttamente il tuo Singleton. Bravo!
    [/php]

    1. Inizializzazione mediante Singleton avanzato
      Sostanzialmente questo metodo non differisce molto dal precedente in quanto prevede la creazione di un'istanza singola di Smarty, tuttavia permette di risparmiare un file in quanto, sfruttando l'ereditarietà, permette di inizializzare i percorsi e tutto il resto direttamente dal suo interno. Nel precedente esempio, difatti, era si new Smarty_smartyStudio(); che a sua volta ridefiniva il costruttore di Smarty craendo appunto un'istanza di tale classe ma abbiamo dovuto definirla in un file separato e includerla. In questo non c'è bisogno di file separati in quanto, nel momento in cui viene chiamato il metodo getInstance(), avviene la creazione di un'istanza della classe stessa che a sua volta ridefinisce il costruttore della classe genitore; più facile a farsi che a dirsi.

    Riprendiamo il codice della classe precedente e modifichiamolo

    [php]
    <?php

    // Questo va cambiato in quanto adesso dobbiamo includere direttamente Smarty
    require_once 'Smarty.class.php';

    // Poi creiamo la nostra classe singleton
    class FactorySingletonSmarty extends Smarty
    {

    /**
     * Dichiariamo un attributo privato per verificare se esiste l'istanza
     * Per convenzione si usa la notazione ungherese
     *
     * @param bool
     * @return bool
     *
     */
    static private $_smartyInstance;
    
    /**
     *
     * Adesso il costruttore va definito
     *
     */
    public function __construct()
    {
    
        // Eredito il costruttore originale
        parent::__construct();
    
            // Setto tutti i percorsi
            $this->setTemplateDir('templates/');
            $this->setCompileDir('templates_c/');
            $this->setConfigDir('configs');
            $this->setCacheDir('cache/');
    
            // Attivo il sistema di cache interno
            $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
    
            // Dichiaro il nome dell'applicazione
            $this->assign('app_name', 'Smarty Studio');
    
    }
    
    /**
     *
     * Mentre si previene come al solito la clonazione
     *
     */
    public function __clone()
    {
    
    }
    
    /**
     *
     * Creiamo il Singleton come metodo statico
     *
     * @return $_SmartyInstance 
     *
     */
    static public function getInstance()
    {
    
        /**
         *
         *    Verifico se esiste l'istanza della classe
         *
         */
        if (!self::$_smartyInstance)
        {
    
            try
            {
    
                /**
                 *
                 *    Anche qua va cambiato in quanto se l'istanza non esiste bisogna creare
                 *  un'istanza di questa stessa classe
                 *
                 */
                self::$_smartyInstance =  new FactorySingletonSmarty();
    
            }
    
                /**
                 *
                 * Mi preparo a gestire le eccezioni.
                 * Da notare che pur quanto Smarty sia dotato di una sua gestione delle eccezioni 
                 * quello che ci stiamo accingendo a gestire non è Smarty stesso ma il Singleton
                 *
                 */
                catch(Excpetion $e)
            {
    
                    /**
                     *
                     * printException non è un metodo di Smarty ma definito da me
                     *
                     */
                    self::printException($e);
    
            }
    
        }
             return self::$_smartyInstance;
    
    }
    
    /**
     *
     *        Rapporto completo dell'errore in caso di eccezione
     *
     */
    static protected function printException($e)
    {
    
        echo '<html><head><title>Messaggio di Errore</title></head><body>';
    
            $trace = '<table border="0"><center>';
                foreach ($e->getTrace() as $file => $b) {
                    foreach ($b as $args => $d) {
                        if ($args == 'args') {
                            foreach ($d as $position => $details) {
                                $trace .= '<tr><td><b>' . strval($file) . '# </b></td><td align="right"><u>args: </u></td> <td><u>'
                              . $position . '</u> : </td><td><i>' . $details . '</i></td></tr>';
                            }        
                        } else {
                            $trace .= '<tr><td><b>' . strval($file) . '# </b></td><td align="right"><u>' . $args
                                   . '</u>:</td><td></td><td><i>' . $d . '</i></td>';
                        }
                    }
                }
                            $trace .= '</center></table>';
                            echo '<br /><br /><center><font face="Verdana"><fieldset style="width: 66%; border: 1px solid black;><legend background="black"><b>[</b>PHP PDO Error '
                                . strval($e->getCode()) . ' <b>]</b></legend><table border="0"><tr><td align="left"><b><u> Message: </u></b></td><td><i> ' . $e->getMessage()
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Code: </u></b></td><td><i> ' . strval($e->getCode())
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>File: </u></b></td><td><i> ' . $e->getFile()
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Line: </u></b></td><td><i> ' . strval($e->getLine())
                                . ' </i></td></tr><br /><tr><td align="left"><b><u>Trace: <br /></u></b></td><td><br /><br />'
                                . $trace . '<br /></td></tr></table></fieldset></center></font>';
                            echo '</body></html>';
                            die();
        
    }
    
    /**
     *
     * Se il debug è attivo vengono lanciate due istanze della classe e vengono confrontate. Se il Singleton funziona sono uguali altrimenti sono diverse
     *
     */
    static public function debug()
    {
    
        $objSmarty = self::getInstance();
        $objSmartyTest = self::getInstance();
            if ($objSmarty === $objSmartyTest)
            {
            
                echo "Ok le istanze sono uguali";
        
            } else {
            
                echo "Si è verificato un errore e le istanze non sono uguali";
        
            }
    
    }    
    

    }

    ?>
    [/php]

    Come facilmente intuibile i file index.php e index.tpl non cambiano suppur sia meglio creare index4.php e index4.tpl a scopo di test
    index4.php

    index4.php
    [php]
    <?php

    // Includiamo il file con il namespace
    require_once 'configure.php';
    // Poi includiamo la classe Factory
    require_once 'Factory.class.php';

    /**
    *

    •    Un semplice controllo per verificare il Singleton
      

    */
    if (FactorySmarty\SINGLE == true) { FactorySingletonSmarty::debug(); }

    try
    {

    /**
     *
     *        Creo un'istanza Singleton di Smarty
     *
     */
    $objSmarty = FactorySingletonSmarty::getInstance();
    
    $objSmarty->assign('name', 'XXX');
    
    /**
     *
     * Decido se attivare o no il debug interno di smarty
     *
     */  
    if (FactorySmarty\DEBUG == true) { $objSmarty->debugging = true; }
    
    /**
     *
     * Visualizzo il risultato
     *
     */
    $objSmarty->display('index3.tpl');
    

    }

    catch (Excpetion $e)
    

    {

    echo "Si è verificato un errore " . $e->getMessage() . "<br />";
    

    }

    ?>
    [/php]

    index4.tpl
    [php]
    {* Smarty *}
    Ciao {$name} hai attivato correttamente il tuo Singleton. Bravo!
    [/php]

    Se volete un' ulteriore prova modificate il metodo debug, attivando l'opzione del file configure.php, come segue:

    [php]
    static public function debug()
    {

        $objSmarty = self::getInstance();
        $objSmartyTest = self::getInstance();
            if ($objSmarty === $objSmartyTest)
            {
            
                var_dump($objSmarty);
                echo "<br /><br /><br /><br /><br /><br />";
                var_dump($objSmartyTest);
                //echo "Ok le istanze sono uguali. objSmarty";
        
            } else {
            
                echo "Si è verificato un errore e le istanze non sono uguali";
        
            }
    
    }    
    

    [/php]

    Al contrario provate a lanciare due istanze singole di Smarty magari in questo modo e confrontarle e vedrete che sono diverse

    [php]
    <?php

    require_once 'Smarty.class.php';
    $objSmarty = new Smarty();
    $objSmartyTest = new Smarty();

    var_dump($objSmarty);
    echo "<br /><br /><br /><br />";
    var_dump($objSmartyTest);

    ?>
    [/php]

    A domani per qualcosa di più approfondito.


  • User

    --> spazio riservato <--


  • User

    --> spazio riservato 1 <--


  • User

    --> spazio riservato 2 <--


  • User

    --> spazio riservato 3 <--


  • User

    --> spazio riservato 4 <--


  • User

    --> spazio riservato 5 <--


  • User

    --> spazio riservato 6 <--


  • User

    --> spazio riservato 7 <--


  • User

    -> spazio riservato 8 <--


  • User Newbie

    questa interessantissima guida non viene + aggiornata ?
    saluti


  • User

    Ad oggi consigliate ancora smarty oppire c'è di meglio?