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

METAL: le macro in PHPTal

Come il namespace Metal consente di aggiungere l'esecuzione delle macro ai template gestiti grazie a PHPTal
Come il namespace Metal consente di aggiungere l'esecuzione delle macro ai template gestiti grazie a PHPTal
Link copiato negli appunti

In questa sede abbiamo già parlato di PHPTal e della semplicità e potenza di questa libreria che permette di utilizzare in PHP il famoso template system di Zope. L'autore della libreria non si è comunque limitato ad effettuare il porting della libreria di base e, per completezza, ha incluso anche i namespace ed i plugin aggiuntivi che hanno reso questo strumento una delle alternative più interessanti nell'ambito dei template engine.

METAL è uno di questi namespace e permette di aggiungere ai propri template il supporto per le macro. Le macro si comportano in modo molto simile alle funzioni; sono blocchi di codice TAL che possono essere richiamati da altre template e possono accettare dei parametri in ingresso.

Gli attributi di metal

Il namespace Metal aggiunge alcuni attributi molto interessanti a TAL, analizziamoli in dettaglio con qualche esempio:

metal:define-marco

Come già facilmente deducibile dal nome, questo attributo è semplicemente utilizzato per dichiarare una macro. Come già accennato in precedenza una macro è come una funzione o, più contestualmente un blocco di template, che è possibile richiamare in altre sedi senza doversi preoccupare di ripetere ogni volta il codice scritto ottenendo una buona riduzione delle operazioni ripetitive. Le macro ereditano le variabili utilizzabili dal contesto in cui sono richiamate.

<div metal:define-macro="user_box">
    <ul>
        <li tal:content="user/username">Username</li>
        <a href="/edit_user">Modifica utente</a>
    </ul>
    <div>
    Ultimo accesso: <span tal:content="user/last_access">Data dell'ultimo accesso</span>
    </div>
</div>

Quando l'engine di PHPTal incontra un tag che contiene l'attributo metal:define-macro non effettua il rendering del codice in esso contenuto ma si limita a salvarlo in memoria in modo che sia possibile richiamarlo successivamente all'interno del template.

metal:use-macro

Con questo attributo si utilizza una macro definita in precedenza attraverso metal:define-macro. Il contenuto della macro richiamata viene quindi incluso come contenuto del tag che richiama la macro. L'attributo metal:use-macro accetta come valore il nome della macro da richiamare; è possibile anche richiamare macro definite in altri file utilizzando come valore il nome del file da cui recuperare la macro seguito da uno slash ('/')e dal nome della macro stessa.

<!--
Presupponiamo che alla template sia assegnato l'array user che
contiene i dati sull'utente corrente
-->

<div metal:define-macro="menu">
    <ul>
        <li><a href="#">Item 1</a></li>
        <li><a href="#" tal:content="custom_item">Item 2</a></li>
    </ul>
</div>

<div metal:use-macro="macros.html/user_box" />
<div tal:define="custom_item string:voce custom"
metal:use-macro="menu" />

Ovviamente il valore dell'attributo può anche contenere delle variabili, richiamate usando la shortcut dell'operatore path: (${ ... }) che abbiamo visto nell'articolo precedente.

metal:define-slot

Degli slot in PHPTal sono delle porzioni di template che possono essere sostituite dinamicamente in fase di esecuzione da arbitrario codice XML. Uno slot deve essere obbligatoriamente definito all'interno della definizione di una macro. Utilizzando il sistema degli slot è possibile creare macro facilmente portabili tra i sistemi che si vanno a sviluppare.

<div metal:define-macro="top_box">
    <div metal:define-slot="news_slot">
        <h3>Ultime news</h3>
        <ul tal:repeat="news latest_news">
            <li href="#" tal:content="news/title" tal:attribute="href news/url">News title</li>
    </ul>
    </div>
</div>

metal:fill-slot

Con questo attributo invece ci si occupa di utilizzare uno slot definito in precedenza all'interno di una macro e di riempirlo con del codice XML.

<div metal:use-macro="boxes.html/top_box">
    <div tal:condition="not: exists: show_news | exists: user" metal:fill-slot="news_slot">
        Benvenuto <b>${user/surname} ${user/name}</b>,<br />
        guarda le <a href="/show_news">ultime news</a>.
    </div>
</div>

Utilizzando il codice precedente otterremo un risultato differente in base al fatto che sia definita la variabile user oppure show_news. Nel caso in cui non sia definito nulla oppure nel caso in cui sia definita la variabile show_news, verrà semplicemente valutata la macro normalmente, e quindi il contenuto del div verrà sostituito con l'elenco delle ultime news. Altrimenti, verrà visualizzato un semplice box contenente i dati dell'utente al posto dello slot che avrebbe dovuto contenere le news.

Utilizzando metal:fill-slot viene solamente sostituito il codice dello slot, mentre il resto della macro viene lasciato inalterato.

Un esempio completo

Vediamo ora un esempio completo in cui utilizzeremo il namespace Metal all'interno dei nostri template PHPTal in modo da rendere il codice riutilizzabile in altre situazioni. Quello che vogliamo fare è visualizzare una lista di semplici messaggi ed una lista news prelevate da un altro sito internet; nel caso in cui l'utente fosse loggato come amministratore visualizzeremo anche dei link per modificare i post ed al posto delle news un menu a tendina per scegliere la fonte di queste ultime. Lo script non sarà completo, ma verranno evidenziate solamente le parti che più ci interessano per comprendere il funzionamento di PHPTal.

Listato 1: il file index.php

<?php

require_once 'PHPTAL.php';
require_once 'mylib.php';

$template = new PHPTAL('template.html');

$template->messages = getMessages();
$template->latest_news = getNews();

$user = getUser();
if(!is_null($user))
{
    $template->user = $user;
    $template->sources = getSources();
}

try {
    echo $template->execute();
}
catch (Exception $e){
    echo $e;
}

?>

Il file index.php PHP include una libreria (mylib.php) che definisce le funzioni utilizzate nel codice per recuperare i dati necessari per il template.

Listato 2: il file template.html

<html>
    <head>
        <title>Test PHPTAL</title>
    </head>
<body>

<div metal:use-macro="macros.html/news_box">
    <div tal:condition="exists: user" metal:fill-slot="news_list">
        <form action="/change_source">
            <select name="source">
            <option value="#"
            tal:repeat="source sources"
            tal:attributes="value source/url"
            tal:content="source/title">Source</option>
            </select>
            <input type="submit" value="salva" />
        </form>
    </div>
</div>

<div tal:repeat="message messages">
    <div>
        <h3 tal:content="message/title">Titolo</h3>
        <p tal:content="message/content">Contenuto</p>
    </div>
    <div tal:condition="exists: user">
        <a href="/edit/${message/id}">Modifica messaggio</a>
    </div>
</div>

</body>
</html>

Il file template.html visualizza la lista dei messaggi recuperati ed include il risultato della macro news_box (definita nel file macros.html) prima di questi. Nel caso in cui l'utente sia connesso viene visualizzato anche un link per la modifica del messaggio e viene riempito lo slot news_list con una select in cui scegliere la sorgente delle ultime news.

Listato 3: il file macros.html

<div metal:define-macro="news_box">

<h3>Ultime news</h3>
    <ul metal:define-slot="news_list">
        <li tal:repeat="news latest_news">
        <a href="#" tal:attributes="href news/url" tal:content="news/title">News 1</a>
        </li>
    </ul>
</div>

Infine il file macros.html dove è definita l'unica macro che utilizziamo nel nostro script di prova.

Per semplicità e per permettervi di anche di testare lo script presentato, includo una semplice implementazione del file mylib.php che si occupa di definire le funzioni che restituiscono gli array associativi utilizzati in fase di rendering.

Listato 4: il file mylib.php

<?php

function getMessages()
{
    return array(
        array('id' => 1, 'title' => 'titolo 1', 'content' => 'contenuto 1'),
        array('id' => 2, 'title' => 'titolo 2', 'content' => 'contenuto 2'),
        array('id' => 3, 'title' => 'titolo 3', 'content' => 'contenuto 3'),
        array('id' => 4, 'title' => 'titolo 4', 'content' => 'contenuto 4')
    );
}

function getUser()
{
    return null;
}

function getNews()
{
    return array(
        array('id' => 1, 'title' => 'titolo 1', 'url' => 'url 1'),
        array('id' => 2, 'title' => 'titolo 2', 'url' => 'url 2')
    );
}

function getSources()
{
    return array(
        array('id' => 1, 'title' => 'titolo 1', 'url' => 'url 1'),
        array('id' => 2, 'title' => 'titolo 2', 'url' => 'url 2')
    );
}

?>

Modificando la funzione getUser in modo da fargli restituire un valore vero, è possibile testare il comportamento del template nel caso in cui venga renderizzata quando un utente è loggato.

Conclusione

Con questo articolo chiudo la mini serie dedicata a PHPTAL nell'esempio mostrato poco fa è stato evidente come la scrittura di template risulti molto semplice usando questo template engine e come i namespace aggiuntivi donino completezza e potenza al sistema. Ci sono altri namespace che non ho trattato ed a cui probabilmente darò spazio nei prossimi articoli. Per chi ne fosse interessato comunque consiglio la lettura della documentazione che, anche se non molto completa, offre comunque una buona panoramica delle funzionalità.

Ti consigliamo anche