Development

Documentation/it_IT/book/1.0/07-Inside-the-View-Layer

You must first sign up to be able to contribute.

Version 13 (modified by giosan, 10 years ago)
--

Capitolo 7 - All'Interno del Layer Vista

La view o vista è responsabile della rappresentazione dell'output legato ad una particolare azione. In symfony, la vista è composta da diverse parti, dove ogni componente è progettato per essere facilmente modificabile dalla persona che lavora con essa.

  • I web designer generalmente lavorano sui template (rappresentazione dei dati di output dell'azione corrente) e sul layout (il contenitore del codice comune a tutte le pagine). Questi sono scritti in HTML ed includono piccole porzioni di codice PHP, che principalmente sono chiamate agli helper.
  • Per questioni di riusabilità, gli sviluppatori solitamente raggruppano queste parti di codice in partial o component. Questi utilizzano gli slot e i component slot per modificare una o più zone del layout. Anche i web designer possono lavorare su queste parti di codice.
  • Gli sviluppatori si occupano del file YAML per la configurazione della view (impostando le proprietà della rappresentazione e degli altri elementi dell'interfaccia) e degli oggetti della rappresentazione. Nei template, lavorando con le variabili, il rischio di cross-site scripting non deve essere ignorato e per questo è richiesta una buona conoscenza delle tecniche di escaping così da garantire la sicurezza dei dati dei vostri utenti.

Qualunque sia il tuo ruolo, troverai strumenti utili per velocizzare il noioso lavoro della gestione della rappresentazione dell'output dell'action. Questo capitolo tratterà tutti questi strumenti.

Templating

Il Listato 7-1 mostra un tipico template di symfony. Esso contiene alcune parti di codice HTML e un po' di semplice codice PHP, solitamente chiamate alle variabili definite nell'action (attraverso $this->name = 'foo';) ed agli helper.

Listato 7-1 - Esempio di un semplice template per indexSuccess.php

[php]
<h1>Welcome</h1>
<p>Welcome back, <?php echo $name ?>!</p>
<ul>What would you like to do?
  <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
  <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
</ul>

Come spiegato nel Capitolo 4, nei template è preferibile usare la sintassi PHP alternativa così da renderli più leggibili anche ai non sviluppatori PHP. Dovresti limitare al minimo il codice PHP nei template, poiché questi file sono quelli utilizzati per realizzare la GUI dell'applicazione e potrebbero essere creati e mantenuti da un altro team specializzato nella rappresentazione ma non nell'application logic. Mantenere la logica all'interno dell'azione rende inoltre più semplice avere diversi template per una sola action, senza duplicarne il codice.

Helper

Gli Helper sono funzioni PHP che generano codice HTML e possono essere usati nei template. Nel Listato 7-1, la funzione link_to() è un helper. A volte, gli helper sono dei salva-tempo, pacchettizzando frammenti di codice usati frequentemente nei template. Per esempio puoi facilmente immaginare la definizione della funzione di questo helper:

[php]
<?php echo input_tag('nickname') ?>
 => <input type="text" name="nickname" id="nickname" value="" />

Potrebbe apparire come nel Listato 7-2.

Listato 7-2 - Esempio di un semplice Helper

[php]
function input_tag($name, $value = null)
{
  return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />';
}

In verità la funzione input_tag() di symfony è leggermente più complicata di questa, dato che accetta un terzo parametro per aggiungere altri attributi al tag <input>. Puoi visionare la completa sintassi e tutte le opzioni sulla documentazione online delle API (http://www.symfony-project.com/api/symfony.html).

Il più delle volte, gli helper con la loro intelligenza ti aiutano nelle lunghe e complesse operazioni di programmazione:

[php]
<?php echo auto_link_text('Please visit our website www.example.com') ?>
 => Please visit our website <a href="http://www.example.com">www.example.com</a>

Gli Helper facilitano il processo di creazione dei template e danno origine al miglior codice HTML possibile in termini di performance ed accessibilità. Puoi sempre continuare ad utilizzare il semplice HTML, ma gli helper solitamente velocizzano la programmazione.

TIP Potresti rimanere sorpreso dal fatto che gli helper vengano denominati tramite l'uso del carattere underscore piuttosto che tramite la convenzione camelCase, globalmente utilizzata in symfony. Questo perché gli helper sono funzioni e tutte le funzioni del core di PHP utilizzano la convenzione della denominazione attraverso il carattere underscore.

Utilizzo degli Helper

I file contenenti le definizioni degli helper non vengono caricati automaticamente (in quanto contengono funzioni e non classi). Gli helper sono raggruppati per scopo. Per esempio, tutte le funzioni helper che hanno a che fare con il testo sono definite in un file chiamato TextHelper.php, chiamato gruppo helper di testo. Così se hai bisogno di utilizzare un helper in un template, devi prima caricarne il gruppo helper relativo dichiarandolo tramite la funzione use_helper() all'interno del template stesso. Il Listato 7-3 mostra un template che utilizza l'helper auto_link_text(), che fa parte del gruppo helper di testo.

Listato 7-3 - Dichiarazione d'uso di un Helper

[php]
// Utilizza uno specifico gruppo di helper in questo template
<?php echo use_helper('Text') ?>
...
<h1>Description</h1>
<p><?php echo auto_link_text($description) ?></p>

TIP Se hai bisogno di richiamare più di un gruppo di helper, puoi aggiungere ulteriori argomenti alla chiamata use_helper(). Per esempio, per caricare sia il gruppo helper di Testo che quello Javascript in un template, utilizza <?php echo use_helper('Text', 'Javascript') ?>.

Alcuni helper sono automaticamente disponibili in ogni template, senza bisogno di dichiararli. Questi sono gli helper facenti parte dei seguenti gruppi di helper:

  • Helper: richiesti per l'inclusione degli helper (la funzione use_helper() è, di fatto, un helper)
  • Tag: helper per tag basilari, utilizzati da quasi ogni helper
  • Url: helper per la gestione di Links e URL
  • Asset: helper per la generazione del sezione <head> nel codice HTML, e forniscono una facile inclusione di assets esterni (immagini, JavaScript, e fogli di stile)
  • Partial: helper che permettono l'inclusione di frammenti di template
  • Cache: helper che manipolano i frammenti di template nella cache
  • Form: helper per la gestione dei Form

La lista degli helper standard, caricati di default in ogni template, è configurabile nel file settings.yml. Così se sai di non aver bisogno degli helper del gruppo helper Cache, o che utilizzerai soltanto quelli del gruppo helper di Testo, modifica l'opzione standard_helpers a tuo piacere. Questo velocizzerà un po' la tua applicazione. Non puoi eliminare i primi quattro gruppi helper della lista precedente (Helper, Tag, Url, e Asset), perché essi sono obbligatori per il corretto funzionamento del motore dei template. Di conseguenza, questi non appaiono neppure nella lista degli helpers standard.

TIP Se mai avessi bisogno di utilizzare un helper al di fuori dei template, puoi sempre caricare il gruppo relativo da qualsiasi punto della tua applicazione richiamando sfLoader::loadHelpers($helpers), dove $helpers è il nome del gruppo helper o un array di nomi dei gruppi. Per esempio, se volessi utilizzare auto_link_text() in una action, dovrai prima richiamare sfLoader::loadHelpers('Text').

Helper utilizzati di frequente

Studierai nel dettaglio alcuni helper nei prossimi capitoli, relazionandoli alle funzionalità che semplificano. Il listato 7-4 mostra una breve lista degli helper utilizzati più spesso, assieme al codice HTML che generano.

Listato 7-4 - Helper comuni

[php]
// Helper group
<?php echo use_helper('NomeHelper') ?>
<?php echo use_helper('NomeHelper1', 'NomeHelper2', 'NomeHelper3') ?>

// Tag group
<?php echo tag('input', array('name' => 'foo', 'type' => 'text')) ?>
<?php echo tag('input', 'name=foo type=text') ?>  // Sintassi alternativa per le opzioni
 => <input name="foo" type="text" />
<?php echo content_tag('textarea', 'dummy content', 'name=foo') ?>
 => <textarea name="foo">dummy content</textarea>

// Url group
<?php echo link_to('click me', 'mymodule/myaction') ?>
=> <a href="/route/to/myaction">click me</a>  // Dipende dalle impostazioni di routing

// Asset group
<?php echo image_tag('myimage', 'alt=foo size=200x100') ?>
 => <img src="/images/myimage.png" alt="foo" width="200" height="100"/>
<?php echo javascript_include_tag('myscript') ?>
 => <script language="JavaScript" type="text/javascript" src="/js/myscript.js"></script>
<?php echo stylesheet_tag('style') ?>
 => <link href="/stylesheets/style.css" media="screen" rel="stylesheet"type="text/css" />

Ci sono molti altri helper in symfony e ci vorrebbe un libro intero per descriverli tutti. Il miglior riferimento per gli helper è la documentazione online delle API (http:// www.symfony-project.com/api/symfony.html), dove tutti gli helper sono ben documentati, con la loro sintassi, opzioni ed esempi.

Aggiungere i tuoi helper

Symfony mette a disposizione un sacco di helper per variscopi, ma se non trovi quello che ti serve nella documentazione delle API, vorrai creare un nuovo helper. Questo è molto semplice da fare.

Le funzioni dell'helper (regolari funzioni PHP che restituiscono codice HTML) dovrebbero essere salvate in un file chiamato FooBarHelper.php, dove FooBar è il nome dell gruppo di helper. Posiziona il file nella directory apps/myapp/lib/helper/ (o in ogni altra directory helper/ creata sotto una delle cartelle lib/ del tuo progetto) in modo da essere automaticamente trovato dall'helper use_helper('FooBar') per essere incluso.

TIP Questo sistema ti permette anche di scavalcare gli helper di symfony esistenti. Per esempio, per ridefinire tutti gli helper del gruppo Testo, basta creare un file TextHelper.php nella tua directory apps/myapp/lib/helper/. Ogni volta che tu usi use_helper('Text'), symfony utilizzerà il tuo gruppo helper piuttosto che il suo. Ma stai attento: visto che il file originale non viene caricato devi ridefinire tutte le funzioni del gruppo helper per scavalcarlo, altrimenti alcuni degli helper originali non saranno per nulla disponibili.

Layout della Pagina

Il template mostrato nel Listato 7-1 non è un documento XHTML valido. La definizione DOCTYPE e i tag <html> e <body> non sono presenti. Questo perché sono posizionati da un'altra parte nell'applicazione, in un file chiamato layout.php, che contiene il layout della pagina. Questo file, chiamato anche template globale, contiene il codice HTML comune a tutte le pagine dell'applicazione per evitare di ripeterlo in ogni template. Il contenuto del template è integrato nel layout, o, se si cambia punto di vista, il layout "decora" il template. Questa è una applicazione del decorator design pattern, illustrato in Figura 7-1.

TIP Per maggiori informazioni riguardo al decorator e altri design patter, vedi Patterns of Enterprise Application Architecture di Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0).

Figura 7-1 - Decorazione di un template con un layout

Decorazione di un template con un layout

Il Listato 7-5 mostra il layout di pagina di default, situato nella directory dell'applicazione templates/.

Listato 7-5 - Layout di default, in myproject/apps/myapp/templates/layout.php

[php]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <?php echo include_http_metas() ?>
  <?php echo include_metas() ?>
  <?php echo include_title() ?>
  <link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>

<?php echo $sf_data->getRaw('sf_content') ?>

</body>
</html>

Gli helper richiamati nella sezione <head> prendono informazioni dal response object e dalla configurazione della view. Il tag <body> estrae il risultato del template. Con questo Layout, la configurazione di default e il template di esempio del Listato 7-1, la view elaborata è simile al Listato 7-6.

Listato 7-6 - Il Layout, la Configurazione della View, e il Template Assemblati

[php]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <meta name="title" content="symfony project" />
  <meta name="robots" content="index, follow" />
  <meta name="description" content="symfony project" />
  <meta name="keywords" content="symfony, project" />
  <title>symfony project</title>
  <link rel="stylesheet" type="text/css" href="/css/main.css" />
  <link rel="shortcut icon" href="/favicon.ico">
</head>
<body>

<h1>Welcome</h1>
<p>Welcome back, <?php echo $name ?>!</p>
<ul>What would you like to do?
  <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
  <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
</ul>

</body>
</html>

Il template globale può essere completamente personalizzato per ogni applicazione. Aggiungi qualsiasi codice HTML di cui hai bisogno. Questo layout è spesso utilizzato per contenere la navigazione del sito, il logo e così via. Puoi anche avere più di un layout e decidere quale deve essere utilizzato per ogni action. Non preoccuparti dell'inclusione di Javascript e fogli di stile per adesso; la sezione "Configurazione della View" più avanti in questo capitolo mostra come occuparsi di ciò.

Scorciatoie nei Template

Nei template alcune variabili di symfony sono sempre disponibili. Queste scorciatoie danno accesso all'informazioni più comunemente necessarie nei template, attraverso gli oggetti base di symfony:

  • $sf_context: l'intero oggetto del contesto (istanza di sfContext)
  • $sf_request: l'oggetto della richiesta (istanza di sfRequest)
  • $sf_params: parametri della richiesta
  • $sf_user: l'attuale oggetto della sessione utente (istanza di sfUser)

Il precedente capitolo ha illustrato dei metodi utili degli oggetti sfRequest e sfUser. Effettivamente puoi chiamare questi metodi nei template tramite le variabili $sf_request e $sf_user. Per esempio, se la richiesta include un parametro total, il suo valore sarà disponibile nel template come segue:

[php]
// Versione lunga
<?php echo $sf_request->getParameter('total'); ?>

// Versione corta
<?php echo $sf_params->get('total'); ?>

// Equivalente al seguente codice dell'action
echo $this->getRequestParameter('total');

Frammenti di Codice

Spesso potresti aver bisogno di includere un po' di codice HTML o PHP in diverse pagine. Per evitare di ripetere quel codice l'istruzione PHP include() il più delle volte è sufficiente.

Per esempio, se molti dei template della tua applicazione hanno bisogno di utilizzare lo stesso frammento di codice, salvalo in un file chiamato myFragment.php nella directory dei template globali (myproject/apps/myapp/templates/) ed includilo nel tuo template come segue:

[php]
<?php include(sfConfig::get('sf_app_template_dir').'/myFragment.php') ?>

Ma questo non è un modo molto pulito per pacchettizzare un frammento, più che altro perché potresti avere differenti nomi di variabile tra il frammento e i vari template che lo includono. In aggiunta il sistema di cache di symfony (descritto nel Capitolo 12) non può in alcun modo rilevare un include, quindi il frammento non può essere messo in cache indipendentemente dal template. Symfony fornisce tre intelligenti tipi diversi di frammenti di codice per rimpiazzare gli include:

  • Se la logica è leggera, vorrai includere un file template che ha accesso agli stessi dati che gli passi. Per far questo utilizzerai un partial.
  • Se la logica è più pesante (per esempio se devi accedere al data model e/o modificare il contenuto conformemente alla sessione), preferirai separare la presentazione dalla logica. Per far ciò utilizzerai un component.
  • se il frammento è scritto per rimpiazzare una specifica parte del layout, per il quale potrebbe già esistere un contenuto standard, utilizzerai un slot.

Note Un altro tipo di frammento di codice, chiamato component slot, deve essere utilizzato quando la natura del frammento dipende dal contesto (per esempio se il frammento deve essere differente per le action di un dato modulo). i component slot sono descritti più avanti in questo capitolo.

L'inclusione di questi frammenti si ottiene tramite gli helper del gruppo Partial. Questi helper sono disponibili in ogni template symfony, senza dichiarazione iniziale.

Partial

Un partial è un pezzo di codice di template riutilizzabile. Per esempio, in una applicazione per pubblicazioni, il codice del template che visualizza un articolo è utilizzata nella pagina del dettaglio dell'articolo e anche nellalista dei migliori articoli e la lista degli ultimi articoli. Questo codice è il prefetto candidato per un partial, come illustrato nella Figura 7-2.

Figure 7-2 - Riutilizzare i partial nei template

Riutilizzare i partial nei template

Come i template i partial sono file posizionati nella directory templates/, e contengono codice HTML con PHP inserito in esso. Il nome del file partial comincia sempre con un underscore (_), questo aiuta a distinguere i partial dai template, visto che sono posizionati nella stessa cartella templates/.

Un template può includere partial sia nel suo stesso modulo, in un altro modulo o nella directory globale templates/. Inserisci un partial utilizzando l'helper include_partial() specificando il modulo e il nome del partialcome parametri (tralasciando l'underscore iniziale e il .php finale), come mostrato nel Listato 7-7.

Listato 7-7 - Includere un Partial in un Template del Modulo mymodule

[php]
// Include il partial myapp/modules/mymodule/templates/_mypartial1.php
// Visto che il template e il partial sono nello stesso modulo,
// puoi omettere in nome del modulo
<?php include_partial('mypartial1') ?>

// Include il partial myapp/modules/foobar/templates/_mypartial2.php
// Il nome del modulo è obbligatorio in questo caso
<?php include_partial('foobar/mypartial2') ?>

// Include il partial myapp/templates/_mypartial3.php
// È considerato parte del modulo 'global'
<?php include_partial('global/mypartial3') ?>

I Partial hanno accesso agli helper di symfony e alle scorciatoie dei template. Anche se i partial possono essere richiamati in qualsiasi parte dell'applicazione, non hanno accesso automatico alle variabili definite nell'action che richiama il template che li include, a meno che non siano passate esplicitamente come argomento. Per esempio se vuoi che un partial abbia accesso alla variabile $total, l'action deve passarla al template e poi il template all'helper come secondo parametro della funzione include_partial(), come mostrato nei Listati 7-8, 7-9 e 7-10.

Listato 7-8 - L'action definisce una variabile , in mymodule/actions/actions.class.php

[php]
class mymoduleActions extends sfActions
{
  public function executeIndex()
  {
    $this->total = 100;
  }
}

Listato 7-9 - Il template passa la variabile al partial, in mymodule/templates/indexSuccess.php

[php]
<p>Hello, world!</p>
<?php include_partial('mypartial',
array('mytotal' => $total)
) ?>

Listato 7-10 - Il partial può ora utilizzare la varabile, in mymodule/templates/_mypartial.php

[php]
<p>Total: <?php echo $mytotal ?></p>

TIP Finora tutti gli helper sono stati richiamati con <?php echo functionName() ?>. L'helper del partial invece è chiamato semplicemente con <?php include_partial() ?>, senza echo, per far in modo che si comporti similmente alla regolare istruzione PHP include(). Semmai avessi bisogno di una funzione che ritorna il contenuto di un partial senza visualizzarla effettivamente, utilizza invece get_partial(). Tutti gli helper include_ descritti in questo capitolo hanno una controparte get_ che può essere richiamata assieme ad una istruzione echo.

Nella nuova versione in sviluppo: invece di risultare in un template, un'action può ritornare un partial. Il metodo renderPartial() della classe dell'action promuove la riusabilità del codice e si avvantaggia della abilità di caching dei partial (vedi Capitolo 12). Le variabili definite dell'action saranno passate automaticamente al partial.

[php]
public function executeIndex()
{
  // do things
  $this->mytotal = 1234;

  return $this->renderPartial('mymodule/mypartial');
}