venerdì, agosto 30, 2013

PHP - Modelli (template)


Questo post fa parte di una serie preparata qualche anno fa per delle lezioni su PHP.

Livello "vista" tramite modelli (template)

Lo sviluppo che segue la modalità nota come MVC prevede una netta separazione tra modello (accesso ai dati), controllore(autenticazione, gestione del chi può fare cosa, ecc.) e vista (forma di presentazione dei dati).
In linea di massima, il modello e il controllo devono limitarsi a estrarre i dati e a fornirli alla vista in forma di semplici variabili (array e oggetti), già pronti per essere rappresentati.

Nella vista, il fatto che i dati derivino da interrogazione di database, da analisi di file XML, o da qualsiasi altra fonte, è assolutamente ininfluente.

Analogamente, il modello non ha idea dello scopo finale per cui vengono richiesti ed estratti dei dati, e li fornirà in maniera il più possibile grezza.

Il controllore ha lo scopo di capire quale interrogazione deve essere fatta e quale forma di visualizzazione adottare. Ad esempio, vengono chiesti i dati sugli articoli che possono essere visualizzati in forma di:
  • pagina web tabellare
  • pagina web con elenco puntato
  • file CSV
  • documento XML
  • ...

La vista si occupa di formattare i dati nella maniera opportuna. In genere, si predispongono dei template (modelli) e il controllore deciderà quale template utilizzare.

Template in PHP (nativi)

Il modo pìù semplice per prediporre dei template è di usare direttamente PHP.

Ad esempio, il file principale (controller) effettuerà le operazioni di estrazione dei dati e richiamerà un template per la visualizzazione.

<?php
$name='George Smith';
$address= '45th & Harris';
include('template.php');

Il file template.php conterrà codice HTML e codice PHP con sintassi alternativa:

<html>
<head>
<title>User Info</title>
</head>
<body>
<p>User Information:<br />
Name: <?php echo $name ?><br />
Address: <?php echo $address ?>
</p>

</body>
</html>

Il risultato sarà, come ci aspettiamo:

User Information: Name: George Smith
Address: 45th & Harris

Vantaggi:
  • non serve imparare un nuovo "linguaggio"
  • non serve installare nessuna libreria di funzioni
  • nel template si possono usare tutte le funzioni di PHP per la formattazione dei dati, non ci sono limiti
Svantaggi:
  • chi prepara il template deve conoscere (almeno un minimo di) PHP
  • i template non sono portabili tra ambienti di sviluppo diversi
  • i template risultano prolissi e poco comprensibili
  • chi prepara il template può comunque eseguire codice PHP "normale" (con eventuali problemi di sicurezza)


Template con codice specifico

In alternativa, si possono usare strumenti per preparare template indipendenti da PHP. Il codice di questi template in genere viene analizzato e tradotto in codice PHP nativo, con la gestione di una cache per evitare di dover fare questa operazione più volte.
Il linguaggio per template più noto è probabilmente quello predisposto per Smarty. Per avere un'idea del suo funzionamento, si può dare un'occhiata al suo crash course. Ci sono però oltre cinquanta progetti per i template di pagine web, non c'è che l'imbarazzo della scelta. È presente anche una tabella di comparazione nella Wikipedia.

Un esempio di codice è il seguente (basato sul crash course, con l'aggiunta dell'indicazione dei percorsi per le directory e la libreria):

<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');
// ovviamente il percorso varia a seconda dell'installazione...

$smarty = new Smarty;

$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';

$smarty->assign('name', 'george smith');
$smarty->assign('address', '45th & Harris');

$smarty->display('index.tpl');

Il template (file index.tpl) corrisponderà al seguente:

<html>
<head>
<title>User Info</title>
</head>
<body>
<p>User Information:<br />
Name: {$name}<br />
Address: {$address}
</p>

</body>
</html>

Il risultato corrisponde a quello precedente.

Smarty: un esempio con un array

Se al template Smarty passiamo un array, possiamo sfruttare il codice per la gestione dell'iterazione.

Il controller sarà simile al seguente:

<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');

$smarty = new Smarty;

$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';

$pictures=array(
    'mountain.jpg',
    'desert.jpg',
    'sea.jpg',
    'lake.jpg',
    'countryside.jpg',
    );

$smarty->assign('title', 'My pictures');
$smarty->assign('pictures', $pictures);

$smarty->display('smarty2_basic.tpl');

Il template sarà invece fatto così:

<html>
<head>
<title>{$title}</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1>{$title}</h1>

<h2>Elenco puntato</h2>

<ul>
{foreach from=$pictures item=picture}
<li>{$picture}</li>
{/foreach}
</ul>

<h2>Testo preformattato</h2>

<pre>
{foreach from=$pictures item=picture}
{$picture}
{/foreach}
</pre>

<h2>Tabella</h2>

<table class="sample">
<tr><th>name</th></tr>
{foreach from=$pictures item=picture}
<tr>
<td>{$picture}</td>
</tr>
{/foreach}
</table>

<h2>Tabella con numero di iterazione</h2>

<table class="sample">
<tr><th>number</th><th>name</th></tr>
{foreach name=picturestable from=$pictures item=picture}
<tr>
<td>{$smarty.foreach.picturestable.iteration}</td>
<td>{$picture}</td>
</tr>
{/foreach}
</table>

<h2>Tabella con colori di sfondo diversi per le righe pari e dispari</h2>

<table class="sample">
<tr><th>name</th></tr>
{foreach name=picturestable from=$pictures item=picture}
<tr>
<td style="background-color: {if $smarty.foreach.picturestable.iteration is even}yellow{else}orange{/if}">{$picture}</td>
</tr>
{/foreach}
</table>

</body>
</html>




Header/Footer o Layout?

Nella predisposizione dei template, si possono usare due strategie: quella di predisporre intestazioni e piè di pagina standard (e di occuparsi dei contenuti) oppure quella di impostare un layout complessivo, in cui è presente un segnaposto per il contenuto specifico.

Header/Footer

Templating basato su Header/Footer (immagine tratta da Practical Symfony)

L'idea di base è che nel template devo incorporare l'intestazione e il piè di pagina. Nella logica di Smarty dovrò scrivere qualcosa tipo:

{include file="header.tpl" title="Main Menu"}
{* qui va il corpo del template *}
{include file="footer.tpl" logo="http://my.example.com/logo.gif"}

Layout

Templating basato su Layout (immagine tratta da Practical Symfony)

L'idea qui è che ci sia un file di layout generico che contiene tutto il codice di base, ad eccezione di quanto comparirà di specifico a seconda dell'azione invocata. 
Nella logica di Smarty avrò un file layout.tpl che contiene il layout generico:

<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<div id="content">
{include file="$action.tpl"}
</div>
</body>
</html>

Il file di layout includerà un file specifico a seconda dell'azione indicata dal controller, che avrà la seguente forma:

<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');
$smarty = new Smarty;

$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';

$pictures=array(
    'mountain.jpg',
    'desert.jpg',
    'sea.jpg',
    'lake.jpg',
    'countryside.jpg',
    );

$smarty->assign('title', 'My pictures');
$smarty->assign('pictures', $pictures);
$smarty->assign('action', 'list');

$smarty->display('layout.tpl');
 
Il file list.tpl sarà quello che caratterizza l'azione specifica:

<h2>The list</h2>
<ul>
{foreach from=$pictures item=picture}
<li>{$picture}</li>
{/foreach}
</ul>

Approfondimenti

Nella predisposizione di modelli (template), è bene tenere presente alcuni concetti che possono tornare utili. Qui userò la terminologia usata con Symfony (altri framework potrebbero usare termini diversi per gli stessi oggetti).

Slot

È una parte del layout il cui valore viene deciso nel momento in cui viene predisposto il contenuto del template relativo all'azione specifica. L'esempio comune è quello del testo del titolo della pagina.

Partial

È una sorta di mini-template che serve per rappresentare una parte dei contenuti e che non ha vita autonoma (non viene richiamato direttamente, almeno di solito, ma da un altro template). È utile per poter sfruttare lo stesso codice in diversi template (un po' come si farebbe con una funzione).

Component

È come un template, con la differenza che usa un'azione specifica e coinvolge quindi il livello del controller.

Flash

È una parte di pagina web che contiene un testo che viene visualizzato una sola volta (al successivo GET scompare), grazie all'uso di cookies. Tipicamente viene utilizzato per dare feedback all'utente sulla riuscita o meno di operazioni che richiedevano l'uso di un POST (visto che il browser viene ridiretto ad un GET).

Helper

Funzioni specifiche che agevolano la preparazione di template (ne esistono per rappresentare date, paesi, misure, messaggi internazionalizzati, ecc.).

Nessun commento:

Posta un commento