Development

Documentation/it_IT/book/1.0/14-Generators (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/it_IT/book/1.0/14-Generators

Show
Ignore:
Author:
Andrea.Giorgini (IP: 213.136.171.99)
Timestamp:
05/28/07 09:18:32 (10 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/it_IT/book/1.0/14-Generators

    v0 v1  
     1= Capitolo 14 - Generatori = 
     2 
     3Molte applicazioni sono basate su dati memorizzati in un database, ed offrono interfacce per la loro gestione. Il noioso e ripetitivo lavoro di creazione di tali moduli fornendo alcune funzionalita' basate su Propel. Se il tuo modello e' definito correttamente, symfony potrebbe anche generare un intero sito di amministrazione. Questo capitolo parlera' dei due generatori inclusi in symfony: scaffolding ed administration generator. Quest'ultimo si basa su di un file di configurazione con una sintassi completa, per cui la maggior parte del presente capitolo descrivera' le varie possibilita' dell'administration generator. 
     4 
     5 
     6== Generazione di codice basata sul modello == 
     7 
     8In un'applicazione web le operazioni di accesso ai dati possono venire catalogate come segue: 
     9 * Creazione di record 
     10 * Selezione di record 
     11 * Modifica di record 
     12 * Eliminazione di record 
     13 
     14Tali operazioni sono talmente comuni da avere un acronimo dedicato: CRUD. Ad esempio, in forum la lista degli ultimi post e' una selezione di record, mentre l'inserimento di una risposta corrisposnde ad un'operazione di creazione. 
     15 
     16Le azioni di base e le template che implementano le operazioni CRUD per una data tabella vengono ripetute continuamente nelle applicazioni web. In symfony, il layer del modello contiene abbastanza informazioni da consentire la generazione del codice per le operazioni CRUD, cosi' da velocizzare molto lo sviluppo di backend. 
     17 
     18Tutti i task di generazione del codice vengono effettuati tramite chiamate alla linea di comando di symfony nella forma seguente: 
     19 
     20{{{ 
     21#!html 
     22<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     23&gt; symfony TASK_NAME APP_NAME MODULE_NAME CLASS_NAME 
     24</div></div> 
     25}}} 
     26 
     27I task di generazione del codice sono {{{propel-init-crud, propel-generate-crud, e propel-init-admin}}}. 
     28 
     29 
     30=== Scaffolding e Administration === 
     31 
     32Durante lo sviluppo, la generazione del codice puo' essere utilizzata per due scopi distinti: 
     33 * Lo Scaffolding e' la struttura base (azioni e template) necessaria alle operazioni CRUD su una tabella. Il codice risultante e' minimale, in quanto pensato come linea guida per uno sviluppo ulteriore. E' una base di partenza che deve essere adattata ai tuoi requisiti di logica e presentazione. Gli scaffolding vengono per lo piu' usati durante lo sviluppo, per fornire un accesso web al database, per costruire un prototipo o per iniziare un modulo basato principalmente su una tabella. 
     34 * Una Adminitrstion e' un'interfaccia sofisticata per la manipolazione dei dati, dedicata all'amministrazione di backend. Essa differisce dallo scaffolding perche' il suo codice non e' pensato per essere modificato manualmente. Una Administration puo' essere personalizzata, estesa, od assemblata tramite configurazione ed ereditarieta'. La sua presentazione e' importante, e si avvantaggia di funzionalita' quali ordinamento, paginazione, e filtri. Essa puo' essere creata e gestita come parte del software pronto per il cliente. 
     35 
     36La linea di comando di symfony usa la parola crud per riferirsi allo scaffolding, ed admin per le administration. 
     37 
     38 
     39=== Inizializzazione o generazione del codice === 
     40 
     41Symfony offre due metodi per generare il codice: per ereditarieta' ({{{init}}}) o per generazione ({{{generate}}}). 
     42 
     43Puoi inizializzare un modulo, che significa creare delle classi vuote che ereditano dal framework. Cio' maschera il codice PHP delle azioni e delle template per evitare che venga modificato. Questo risulta utile se la tua struttura dati non e' ancora completata, o se hai semplicemente bisogno di una veloce interfaccia al db per gestirne i dati. Il codice eseguito run-time non e' situato nella tus applicazione ma nella cache. I task della linea di comando per questo tipo di generazione cominciano con {{{propel-init-}}}. 
     44 
     45Il codice delle azioni inizializzate e' vuoto. Ad esempio, un modulo {{{article}}} inizializzato ha azioni del tipo: 
     46 
     47{{{ 
     48#!php 
     49class articleActions extends autoarticleActions 
     50{ 
     51} 
     52}}} 
     53 
     54D'altra parte, puoi anche generare il codice delle azioni e delle template, per poi modificarli. Il modulo che ne risulta e' percio' indipendente dalle classi del framework, e non puo' essere modificato tramite file di configurazione. I task della linea di comando per questo tipo di generazione cominciano con {{{propel-generate-}}}. 
     55 
     56Dato che gli scaffolding sono pensati per servire come base ad ulteriori sviluppi, spesso sono la generazione per essi risulta essere la scelta migliore. D'altra parte, una administration e' facile da aggiornare tramite una modifica della configurazione, e rimane usabile anche se il modello cambia. Ecco perche' le administration vengono inizializzate. 
     57 
     58 
     59=== Esempio di modello dei dati === 
     60 
     61Durante questo capitolo i listati mostreranno le funzionalita' dei generatori basandosi su un semplice esempio, che ti ricordera' il Capitolo 8. Si tratta del noto esempio di applicazione weblog, contenente le due classi {{{Article}}} e {{{Comment}}}. Il Listato 14-1 ne mostra lo schema, illustrato in Figura 14-1. 
     62 
     63''Listato 14-1 - {{{schema.yml}}} di un esempio di weblog'' 
     64 
     65{{{ 
     66#!php 
     67propel: 
     68  blog_article: 
     69    _attributes: { phpName: Article } 
     70    id: 
     71    title:       varchar(255) 
     72    content:     longvarchar 
     73    created_at: 
     74  blog_comment: 
     75    _attributes: { phpName: Comment } 
     76    id: 
     77    article_id: 
     78    author:      varchar(255) 
     79    content:     longvarchar 
     80    created_at: 
     81}}} 
     82 
     83''Figura 14-1 - Esempio di modello dei dati'' 
     84 
     85{{{ 
     86#!html 
     87<img src="http://www.symfony-project.com/images/book/trunk/F1401.png" /> 
     88}}} 
     89 
     90Non c'e' una regola particolare da seguire durante la creazione dello schema per permettere la generazione del codice. Symfony utilizzera' lo schema cosi' com'e' ed interpretera' i suoi attributi per generare uno scaffolding od una administration. 
     91 
     92{{{ 
     93#!html 
     94<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/tip.gif) no-repeat 5px 10px; border: 1px solid #ddd;"><p> 
     95Per recepire il meglio di questo capitolo sarebbe meglio che tu mettessi in pratica gli esempi. Avrai una panoramica migliore del codice generato da symfony e cosa puo' essere fatto con esso se segui passo passo gli esempi dei listati. Per cui sei invitato a creare una struttura dati come quella descritta precedentemente per creare un database con le tabelle <code>blog_article</code> e <code>blog_comment</code>, ed a popolarlo con dati di esempio. 
     96</p></blockquote> 
     97}}} 
     98 
     99 
     100== Scaffolding == 
     101 
     102Lo scaffolding e' di grande utilita' durante i primi giorni di sviluppo. Con un semplice comando, symfony crea un intero modulo basato sulla descrizione di una data tabella. 
     103 
     104 
     105=== Generazione di uno scaffolding === 
     106 
     107Per generare lo scaffolding del modulo {{{article}}} basato sul modello della classe {{{Article}}} digita: 
     108 
     109{{{ 
     110#!html 
     111<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     112&gt; symfony propel-generate-crud myapp article Article 
     113</div></div> 
     114}}} 
     115 
     116Symfony legge la definizione della classe {{{Article}}} nello {{{schema.yml}}} e su di essa crea un set di template ed azioni nella cartella {{{myapp/modules/article/}}}. 
     117 
     118Il modulo generato contiene tre viste. Navigando sulla pagina {{{http://localhost/myapp_dev.php/article}}}, la vista {{{list}}}, che e' quella di default, visualizza le righe della tabella {{{blog_article}}} come mostrato in Figura 14-2. 
     119 
     120''Figura 14-2 - Vista {{{list}}} del modulo {{{article}}}'' 
     121 
     122{{{ 
     123#!html 
     124<img src="http://www.symfony-project.com/images/book/trunk/F1402.png" /> 
     125}}} 
     126 
     127Cliccando sull'id di un articolo viene mostrata la vista {{{show}}}. In pratica i dettagli di un articolo, come in Figura 14-3. 
     128 
     129''Figura 14-3 - Vista {{{show}}} del modulo {{{article}}}'' 
     130 
     131{{{ 
     132#!html 
     133<img src="http://www.symfony-project.com/images/book/trunk/F1403.png" /> 
     134}}} 
     135 
     136 
     137Sia modificando un articolo cliccando sul link edit, sia creando un nuovo articolo tramite il link create, verrà visualizzata la vista {{{edit}}}, riprodotta in Figura 14-4. 
     138 
     139Utilizzando tale modulo puoi sia creare nuovi articoli che modificarne o cancellarne esistenti. Il codice generato è una buona base per sviluppi futuri. Il Listato 14-2 elenca le azioni e le template generate per il nuovo modulo. 
     140 
     141''Figura 14-4 - Vista edit del modulo {{{Article}}}'' 
     142{{{ 
     143#!html 
     144<img src="http://www.symfony-project.com/images/book/trunk/F1404.png" /> 
     145}}} 
     146 
     147''Listato 14-2 - Elementi CRUD generati, in {{{myapp/modules/article/}}}'' 
     148{{{ 
     149#!php 
     150// In actions/actions.class.php 
     151index           // Forward alla seguente azione list 
     152list            // Mostra la  lista di tutti i record della tabella 
     153show            // Mostra la lista di tutte le colonne di un record 
     154edit            // Mostra una form per modificare le colonne di un record 
     155update           // Azione chiamata dalla form dell'azione edit 
     156delete           // Elimina un record 
     157create           // Crea un nuovo record 
     158 
     159// In templates/ 
     160editSuccess.php  // Form per la modifica di un record (Vista edit) 
     161listSuccess.php  // Lista di tutti i record (Vista list) 
     162showSuccess.php  // Dettagli di un record (Vista show) 
     163}}} 
     164 
     165La logica di tali azioni e template è abbastanza semplice ed esplicita, per cui invece di spiegarle tutte nei dettagli, il Listato 14-3 mostra giusto una parte della classe generata. 
     166 
     167''Listato 14-3 - Classe generata, in {{{myapp/modules/article/actions/actions.class.php}}}'' 
     168{{{ 
     169#!php 
     170class articleActions extends sfActions 
     171{ 
     172  public function executeIndex() 
     173  { 
     174    return $this->forward('article', 'list'); 
     175  } 
     176  
     177  public function executeList() 
     178  { 
     179    $this->articles = ArticlePeer::doSelect(new Criteria()); 
     180  } 
     181  
     182  public function executeShow() 
     183  { 
     184    $this->article = ArticlePeer::retrieveByPk($this->getRequestParameter('id')); 
     185    $this->forward404Unless($this->article); 
     186  } 
     187  ... 
     188}}} 
     189 
     190Per avere un'applicazione di base funzionante basta semplicemente che tu modifichi il codice generato per soddisfare i tuoi requisiti e che ripeta la generazione CRUD per tutte le tabelle con cui vuoi interagire. Generare uno scaffolding velocizza veramente lo sviluppo di un'applicazione: lascia a symfony il lavoro sporco e concentrati sulle specifiche e sulle interfacce. 
     191 
     192 
     193=== Inizializzazione di uno scaffolding === 
     194 
     195L'inizializzazione di uno scaffolding è particolarmente utile quando devi verificare di poter accedere ai dati memorizzati nel database. E' veloce da costruire ed altrettano veloce da eliminare quando sarai sicuro del corretto funzionamento della tua applicazione. 
     196 
     197Per inizializzare uno scaffolding Propel che creerà un modulo {{{article}}} che gestisca i record della classe {{{Article}}}, digita: 
     198 
     199{{{ 
     200#!html 
     201<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     202&gt; symfony propel-init-crud myapp article Article 
     203</div></div> 
     204}}} 
     205 
     206Potrai quindi accedere alla vista {{{list}}} tramite l'azione di default: 
     207 
     208{{{ 
     209#!php 
     210http://localhost/myapp_dev.php/article 
     211}}} 
     212 
     213Le pagine risultanti sono esattamente le stesse di quelle di uno scaffolding generato. Le puoi usare come una semplice interfaccia web al db. 
     214 
     215Se dai un'occhiata all'appena creata {{{actions.class.php}}} del modulo {{{Article}}}, vedrai che essa è vuota: viene tutto ereditato da una classe auto-generata. Lo stesso succede per le template: nella cartella {{{templates/}}} non troverai alcun file. Il codice delle classi e template inizializzate è lo stesso di quelle generate, ma in questo caso esso risiede nella cache dell'applicazione ({{{myproject/cache/myapp/prod/module/autoArticle/}}}). 
     216 
     217Durante lo sviluppo di un'applicazione, gli sviluppatori inizializzano uno scaffolding per interagire con i dati senza pensare all'interfaccia. Il codice non è pensato per essere personalizzato; uno scaffolding inizializzato può essere visto come una semplice alternativa a phpMyAdmin per gestire i dati. 
     218 
     219 
     220== Administration == 
     221 
     222Per il backend della tua applicazione symfony può generare anche moduli più avanzati, ma sempre bassandosi sul file {{{schema.yml}}}. Puoi creare un intero sito di amministrazione tramite i moduli generati. Gli esempi di questa sezione descriveranno i moduli di amministrazione di un'applicazione di backend. Se il tuo progetto non ha un'applicazione di backend, creane lo scheletro adesso tramite il task {{{init-app}}}: 
     223 
     224{{{ 
     225#!html 
     226<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     227&gt; symfony init-app backend 
     228</div></div> 
     229}}} 
     230 
     231I moduli di amministrazione interpretano il modello tramite un file di configurazione particolare chiamato {{{generator.yml}}}, che può essere modificato per estendere i componenti generati ed il look and feel del modulo. Tali moduli beneficiano dei meccanismi descritti nei capitoli precedenti (layout, validation, routing, configurazioni personalizzate, autoloading, e così via). Puoi inoltre fare l'override delle azioni o template generate, per poter integrare nell'amministrazione generate le tue proprie funzionalità, ma {{{generator.yml}}} si dovrebbe occupare dei requisiti più comuni e restringere il codice PHP solo a necessità specifiche. 
     232 
     233 
     234=== Inizializzazione di un modulo di amministrazione === 
     235 
     236In symfony costruisci un'amministrazione per modulo. Esso viene generato tramite un'oggetto Propel utilizzando il task {{{propel-init-admin}}}, che usa una sintassi simile a quella dell'inizializzazione di uno scaffolding: 
     237 
     238{{{ 
     239#!html 
     240<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     241&gt; symfony propel-init-admin backend article Article 
     242</div></div> 
     243}}} 
     244 
     245Questa chiamata è sufficiente a creare il modulo {{{article}}} nell'applicazione di backend basato sulla definizione della classe {{{Article}}}, accessibile tramite: 
     246 
     247{{{ 
     248#!php 
     249http://localhost/backend.php/article 
     250}}} 
     251 
     252Il look and feel del modulo generato, illustrato nelle Figure 14-5 e 14-6, è abbastanza sofisticato da essere usato così com'è in un'applicazione commerciale. 
     253 
     254''Figura 14-5 - Vista {{{list}}} del modulo {{{aticle}}} nell'applicazione di backend'' 
     255{{{ 
     256#!html 
     257<img src="http://www.symfony-project.com/images/book/trunk/F1405.png" /> 
     258}}} 
     259 
     260''Figura 14-6 - Vista {{{edit}}} del modulo {{{aticle}}} nell'applicazione di backend'' 
     261{{{ 
     262#!html 
     263<img src="http://www.symfony-project.com/images/book/trunk/F1406.png" /> 
     264}}} 
     265 
     266La differenza tra l'interfaccia di uno scaffolding ed un'amministrazione potrebbe non essere molto significativa fino ad ora, ma la configurabilità dell'amministrazione ti permetterà di migliorare il layout di base senza scrivere una linea di PHP. 
     267 
     268{{{ 
     269#!html 
     270<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/note.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     271<p> 
     272I moduli di amministrazione possono essere esclusivamente inizializzati (non generati) 
     273</p></blockquote> 
     274}}} 
     275 
     276 
     277=== Un'occhiata al codice generato === 
     278 
     279Il file del modulo di amministrazione Article, nella cartella {{{apps/backend/modules/article/}}}, è vuoto in quanto inizializzato. Il modo migliore per rivedere il codice generato di questo modulo è visualizzare il sorgente della pagina nel browser, per poi quindi controllare il contenuto della cartella {{{cache/}}}. 
     280Il Listato 14-4 elenca le azioni e template generate trovate nella cache. 
     281 
     282''Listato 14-4 - Elementi dell'amministrazione generata, in {{{cache/backend/ENV/modules/article/}}}'' 
     283{{{ 
     284#!php 
     285// In actions/actions.class.php 
     286create           // Forward a edit 
     287delete            // Elimina un record 
     288edit             // Mostra una form per modificare i campi di un record e gestire la submit della form 
     289index            // Forward a list 
     290list             // Visualizza la lista di tutti i record di una tabella 
     291save             // Forward a edit 
     292 
     293// In templates/ 
     294_edit_actions.php 
     295_edit_footer.php 
     296_edit_form.php 
     297_edit_header.php 
     298_edit_messages.php 
     299_filters.php 
     300_list.php 
     301_list_actions.php 
     302_list_footer.php 
     303_list_header.php 
     304_list_messages.php 
     305_list_td_actions.php 
     306_list_td_stacked.php 
     307_list_td_tabular.php 
     308_list_th_stacked.php 
     309_list_th_tabular.php 
     310editSuccess.php 
     311listSuccess.php 
     312}}} 
     313 
     314Ciò mette in evidenza che un modulo di amministrazione generato è composto essenzialmente di due viste, {{{edit}}} e {{{list}}}. Se dai un'occhiata al codice, lo troverai estremamente modulare, leggibile ed estendibile. 
     315 
     316 
     317=== Introduzione al file di configurazione generator.yml === 
     318 
     319La differenza principale tra scaffolding e amministrazioni (a parte la mancanza dell'azione {{{show}}} per le amministrazioni) è che quest'ultime si basano su parametri del file di configurazione YAML {{{generator.yml}}}. Per vedere la configurazione di default del modulo di amministrazione appena generato, apri il file {{{generator.yml}}} situato nella cartella {{{backend/modules/article/config/generator.yml}}} e riprodotto nel Listato 14-5. 
     320 
     321''Listato 14-5 - Configurazione di default del generatore, in {{{backend/modules/article/config/generator.yml}}}'' 
     322{{{ 
     323#!php 
     324generator: 
     325  class:              sfPropelAdminGenerator 
     326  param: 
     327    model_class:      Article 
     328    theme:            default 
     329}}} 
     330 
     331Ciò è sufficiente per generare un'amministrazione di base. Tutte le personalizzazioni vanno aggiunte sotto la chiave {{{param}}}, dopo la linea {{{theme}}} (ciò significa che tutte le linee aggiunte al file {{{generator.yml}}} devono essere precedute da minimo quattro spazi bianchi, per essere indentate correttamente). Il Listato 14-6 mostra un tipico {{{generator.yml}}} personalizzato. 
     332 
     333''Listato 14-6 - Configurazione tipica di un generatore completo'' 
     334{{{ 
     335#!php 
     336generator: 
     337  class:              sfPropelAdminGenerator 
     338  param: 
     339    model_class:      Article 
     340    theme:            default 
     341 
     342    fields: 
     343      author_id:      { name: Article author } 
     344 
     345    list: 
     346      title:          Lista di tutti gli articoli 
     347      display:        [title, author_id, category_id] 
     348      fields: 
     349        published_on: { params: date_format='dd/MM/yy' } 
     350      layout:         stacked 
     351      params:         | 
     352        %%is_published%%<strong>%%=title%%</strong><br /><em>da %%author%% 
     353        in %%category%% (%%published_on%%)</em><p>%%content_summary%%</p> 
     354      filters:        [title, category_id, author_id, is_published] 
     355      max_per_page:   2 
     356 
     357    edit: 
     358      title:          Modifica articolo "%%title%%" 
     359      display: 
     360        "Post":       [title, category_id, content] 
     361        "Workflow":   [author_id, is_published, created_on] 
     362      fields: 
     363        category_id:  { params: disabled=true } 
     364        is_published: { type: plain} 
     365        created_on:   { type: plain, params: date_format='dd/MM/yy' } 
     366        author_id:    { params: size=5 include_custom=>> Scegli un autore << } 
     367        published_on: { credentials:  } 
     368        content:      { params: rich=true tinymce_options=height:150 } 
     369}}} 
     370 
     371La sezione seguente spiega in dettaglio i parametri che possono essere utilizzati in questo file di configurazione. 
     372 
     373 
     374=== Configurazione del generatore === 
     375 
     376La configurazione del generatore è molto potente, e ti da la possibilità di modificare l'amministrazione generata in diversi modi. Ma tali funzionalità hanno un prezzo: la sintassi è complessivamente lunga e difficile da imparare, rendendo questo capitolo uno dei più lunghi del libro. Il sito di symfony propone una risorsa alternativa che ti aiuterà ad imparare tale sintassi: il reference card, riprodotto in Figura 14-7. 
     377Scaricalo da [http://www.symfony-project.com/uploads/assets/sfAdminGeneratorRefCard.pdf], e tienilo vicino a te quando leggerai gli esempi seguenti di questo capitolo. 
     378 
     379Gli esempi di questa sezione riguarderanno i moduli di amministrazione di {{{article}}} e {{{comment}}}, basati sulla classe {{{Comment}}}. Crea il secondo con il task {{{propel-init-admin}}}: 
     380 
     381{{{ 
     382#!html 
     383<div style="height: 30px; background-color:#333; color:#eee;"><div style="float: left; font-family: Monospace; margin-top: 6px; margin-left: 10px;"> 
     384&gt; symfony propel-init-admin backend comment Comment 
     385</div></div> 
     386}}} 
     387 
     388''Figura 14-7 - La reference card per il generatore di amministrazione'' 
     389{{{ 
     390#!html 
     391<img src="http://www.symfony-project.com/images/book/trunk/F1407.png" /> 
     392}}} 
     393 
     394=== Campi === 
     395 
     396Per default, i campi delle viste {{{list}}} ed {{{edit}}} sono le colonne definite in {{{schema.yml}}}. Con {{{generator.yml}}}, puoi scegliere quali campi visualizzare, quali nascondere, ed aggiungere campi personalizzati anche se non hanno una corrispondenza nel modello. 
     397 
     398 
     399==== Settaggi dei campi ==== 
     400 
     401Il generatore crea un {{{field}}} per ogni colonna del file {{{schema.yml}}}. Sotto la chiave {{{fields}}}, puoi modificare il modo in cui il campo è visualizzato, formattato, ecc. Ad esempio, i settaggi del campo mostrati nel Listato 14-7 definiscono per il campo {{{title}}} un nome di classe personalizzato ed una textarea, mentre per il campo {{{content}}} un suggerimento ed un nome personalizato. La sezione seguente descriverà in dettaglio ogni parametro. 
     402 
     403''Listato 14-7 - Impostare un nome personalizzato per una colonna'' 
     404{{{ 
     405#!php 
     406generator: 
     407  class:              sfPropelAdminGenerator 
     408  param: 
     409    model_class:      Article 
     410    theme:            default 
     411 
     412    fields: 
     413      title:          { name: Article Title, type: textarea_tag, params: class=foo } 
     414      content:        { name: Body, help: Fill in the article body } 
     415}}} 
     416 
     417In aggiunta a tale definizione di default per tutte le viste, puoi fare l'override delle impostazioni di un campo per una vista specifica ({{{list}}} e {{{edit}}}), come dimostrato dal Listato 14-8. 
     418 
     419''Listato 14-8 - Override delle impostazioni globali vista per vista'' 
     420{{{ 
     421#!php 
     422generator: 
     423  class:              sfPropelAdminGenerator 
     424  param: 
     425    model_class:      Article 
     426    theme:            default 
     427 
     428    fields: 
     429      title:          { name: Article Title } 
     430      content:        { name: Body } 
     431 
     432    list: 
     433      fields: 
     434        title:        { name: Title } 
     435 
     436    edit: 
     437      fields: 
     438        content:      { name: Body of the article } 
     439}}} 
     440 
     441Questo è un principio generale: qualsiasi impostazione per l'intero modulo sotto la chiave {{{fields}}} può venire overridata da una specifica vista ({{{list}}} ed {{{edit}}}) seguente. 
     442 
     443 
     444==== Aggiungere campi alla visualizzazione ==== 
     445 
     446I campi definiti nella sezione {{{fields}}} possono essere visualizzati, nascosti, ordinati e raggruppati in varie forme per ogni vista. La chiave {{{display}}} viene utilizzata a tale scopo. Ad esempio, per riordinare i campi del modulo {{{comment}}} usa il codice del listato 14-9. 
     447 
     448''Listato 14-9 - Selezionare i campi da visualizzare, in {{{in modules/comment/config/generator.yml}}}'' 
     449{{{ 
     450#!php 
     451generator: 
     452  class:              sfPropelAdminGenerator 
     453  param: 
     454    model_class:      Comment 
     455    theme:            default 
     456 
     457    fields: 
     458      article_id:     { name: Article } 
     459      created_at:     { name: Published on } 
     460      content:        { name: Body } 
     461 
     462    list: 
     463      display:        [id, article_id, content] 
     464 
     465    edit: 
     466      display: 
     467        NONE:         [article_id] 
     468        Editable:     [author, content, created_at] 
     469}}} 
     470 
     471La {{{list}}} mostrerà quindi tre colonne, come in Figura 14-8, e la form di {{{edit}}} presenterà quattro campi, assemblati in due gruppi, come in Figura 14-9. 
     472 
     473''Figura 14-8 - Selezionare colonne nella vista {{{list}}} del modulo {{{comment}}}'' 
     474{{{ 
     475#!html 
     476<img src="http://www.symfony-project.com/images/book/trunk/F1408.png" /> 
     477}}} 
     478 
     479''Figura 14-9 - Raggruppare campi nella vista {{{edit}}} del modulo {{{comment}}}'' 
     480{{{ 
     481#!html 
     482<img src="http://www.symfony-project.com/images/book/trunk/F1409.png" /> 
     483}}} 
     484 
     485Per cui puoi utilizzare le impostazioni di {{{display}}} in due modi: 
     486 * Per selezionare le colonne da visualizzare e l'ordine nel quale devono apparire, metti i campi in un semplice array, come nella precedente vista {{{list}}}. 
     487 * Per raggruppare campi, usa un array associativo con il nome del gruppo come chiave, oppure NONE per un gruppo senza nome. Il valore è di nuovo un array ordinato di nomi di colonne. 
     488 
     489{{{ 
     490#!html 
     491<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/tip.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     492<p> 
     493Per default, la chiave primaria non appare in alcuna vista. 
     494</p></blockquote> 
     495}}} 
     496 
     497 
     498==== Campi personalizzati ==== 
     499 
     500In pratica, i campi configurati in {{{generator.yml}}} non hanno bisogno di corrispondere effettivamente alle colonne dello schema. Se la classe relativa offre un getter personalizzato, puè essere usato come campo per la vista {{{list}}}; se c'è un getter e/o un setter, può essere usato per la {{{edit}}}. Ad esempio, puoi estendere il modello di {{{Article}}} con un metodo {{{getNbComments()}}} simile a quello del Listato 14-10. 
     501 
     502''Listato 14-10 - Aggiungere un getter nel modello, in {{{lib/model/Article.class.php}}}'' 
     503{{{ 
     504#!php 
     505public function getNbComments() 
     506{ 
     507  return $this->countComments(); 
     508} 
     509}}} 
     510 
     511Dopodichè {{{nb_comments}}} è disponibile come campo nel modulo generato (nota che il getter utilizza una versione camelCase del nome del campo), come nel Listato 14-11. 
     512 
     513''Listato 14-11 - Getter personallizati forniscono colonne aggiuntive nei moduli di amministrazione, in {{{backend/modules/article/config/generator.yml}}}'' 
     514{{{ 
     515#!php 
     516generator: 
     517  class:              sfPropelAdminGenerator 
     518  param: 
     519    model_class:      Article 
     520    theme:            default 
     521 
     522    list: 
     523      display:        [id, title, nb_comments, created_at] 
     524}}} 
     525 
     526La risultante vista {{{list}}} del modulo {{{article}}}  mostrata in Figura 14-10. 
     527 
     528''Figura 14-10 - Campo personalizzato nella vista {{{list}}} del modulo {{{article}}}'' 
     529{{{ 
     530#!html 
     531<img src="http://www.symfony-project.com/images/book/trunk/F1410.png" /> 
     532}}} 
     533 
     534Campi personalizzati possono anche restituire codice HTML per visualizzare qualcosa di più di dati grezzi. Ad esempio, puoi estendere la classe {{{Comment}}} con un metodo {{{getArticleLink()}}} come mostrato nel Listato 14-12. 
     535 
     536''Listato 14-12 - Aggiungere un getter personalizzato che restituisce HTML, in {{{lib/model/Comment.class.php}}}'' 
     537{{{ 
     538#!php 
     539public function getArticleLink() 
     540{ 
     541  return link_to($this->getArticle()->getTitle(), 'article/edit?id='.$this->getArticleId()); 
     542} 
     543}}} 
     544 
     545Puoi usare questo nuovo getter come campo personalizzato nella vista {{{comment/list}}} con la stessa sintassi del Listato 14-11. Vedi l'esempio nel Listato 14-13, ed il risultato in Figura 14-11, dove il codice HTML in output dal getter (un link all'articolo) viene mostrato nella seconda colonna al posto della chiave primaria dell'articolo. 
     546 
     547''Listato 14-13 - Getter personalizzati che restituiscono HTML possono anche essere usati come colonne aggiuntive, in {{{modules/comment/config/generator.yml}}}'' 
     548{{{ 
     549#!php 
     550generator: 
     551  class:              sfPropelAdminGenerator 
     552  param: 
     553    model_class:      Comment 
     554    theme:            default 
     555 
     556    list: 
     557      display:        [id, article_link, content] 
     558}}} 
     559 
     560''Figura 14-11 - Campo personalizzato nella vista {{{list}}} del modulo {{{comment}}}'' 
     561{{{ 
     562#!html 
     563<img src="http://www.symfony-project.com/images/book/trunk/F1411.png" /> 
     564}}} 
     565 
     566 
     567==== Campi partial ==== 
     568 
     569Il codice situato nel modello deve essere indipendente dalla presentazione. L'esempio precedente del metodo {{{getArticleLink()}}} non rispetta il principio della separazione dei livelli, in quanto codice della vista compare nel modello. Per raggiungere lo stesso scopo in modo corretto, dovresti mettere il codice che stampa l'HTML per un campo personalizzato in un partial. Fortunatamente, il generatore di amministrazione ti permette di specificare il nome di un campo preceduto da un prefisso con underscore. In questo caso, il file {{{generator.yml}}} del Listato 14-13 verrebbe modificato come nel Listato 14-14. 
     570 
     571''Listato 14-14 - I partial possono essere usati come colonne aggiuntive - usa il {{{_prefisso}}}'' 
     572{{{ 
     573#!php 
     574  list: 
     575      display:        [id, _article_link, created_at] 
     576}}} 
     577 
     578Per funzionare, il partial {{{_article_link.php}}} deve essere posizionato nella cartella {{{modules/comment/templates/}}}, come nel Listato 14-15. 
     579 
     580''Listato 14-15 - Esempio di partial per la vista {{{list}}}, in {{{modules/comment/templates/_article_link.php}}}'' 
     581{{{ 
     582#!php 
     583<?php echo link_to($comment->getArticle()->getTitle(), 'article/edit?id='.$comment->getArticleId()) ?> 
     584}}} 
     585 
     586Nota che la template partial di un campo partial ha accesso all'oggetto corrente tramite una variabile che ha lo stesso nome della classe (in questo esempio {{{$comment}}}). Ad esempio, per un modulo costruito per una classe chiamata {{{UserGroup}}}, il partial avrà accesso all'oggetto corrente tramite la variabile {{{$user_group}}}. 
     587 
     588Il risultato è lo stesso della Figura 14-11, a parte che stavolta viene rispettata la separazione dei livelli. Se ti abitui a tale meccanismo, avrai applicazioni molto più manutenibili. 
     589 
     590Se avessi bisogno di personalizzare parametri per un partial, fai lo stesso come per i campi normali, sotto la chiave {{{field}}}. Semplicemente non includere l'underscore iniziale, come nell'esempio del Listato 14-16. 
     591 
     592''Listato 14-16 - Le proprietà di un partial possono essere personalizzate sotto la chiave {{{fields}}}'' 
     593{{{ 
     594#!php 
     595  fields: 
     596        article_link:   { name: Article } 
     597}}} 
     598 
     599Se il tuo partial contiene una logica complicata, probabilmente lo vorrai sostituire con un component. Cambia il prefisso da {{{_}}} a {{{~}}} ed il gioco è fatto, come puoi vedere dal Listato 14-17. 
     600 
     601''Listato 14-17 - I componenti possono essere usati come colonne aggiuntive - usa il {{{~prefisso}}}'' 
     602{{{ 
     603#!php 
     604... 
     605    list: 
     606      display:        [id, ~article_link, created_at] 
     607}}} 
     608 
     609Nella template generata, questo sfocierà in una chiamata al component {{{articleLink}}} del modulo corrente. 
     610 
     611{{{ 
     612#!html 
     613<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/note.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     614<p> 
     615Campi personalizzati e partial possono essere usati nelle viste <code>list</code> ed <code>edit</code>, e per i filtri. Se usi lo stesso partial per diverse viste, il contesto ('list', 'edit', o 'filter') è memorizzato nella variabile <code>$type</code>. 
     616</p></blockquote> 
     617}}} 
     618 
     619 
     620=== Personalizzazione della vista === 
     621 
     622Per cambiare il modo in cui appaiono le viste {{{edit}}} e {{{list}}} potresti essere tentato di cambiarne le template. Ma dato che esse vengono generate, non è una bella idea. Invece dovresti usare il file di configurazione {{{generator.yml}}} in quanto può fare quasi tutto quel che ti serve senza sacrificare la modularità. 
     623 
     624 
     625==== Cambiare il titolo della vista ==== 
     626 
     627In aggiunta ai campi personalizzati, le pagine {{{edit}}} e {{{list}}} possono avere un titolo di pagina anch'esso personalizzato. Ad esempio, se tu volessi cambiare il titolo della vista {{{articles}}}, dovresti fare come nel Listato 14-18. Il risultato è illustrato in Figura 14-12. 
     628 
     629''Listato 14-18 - Impostare un titolo personalizzato per ogni vista, in {{{backend/modules/article/config/generator.yml}}}'' 
     630{{{ 
     631#!php 
     632  list: 
     633      title:          List of Articles 
     634      ... 
     635 
     636    edit: 
     637      title:          Body of article %%title%% 
     638      display:        [content] 
     639}}} 
     640 
     641''Figura 14-12 - Titolo della vista {{{edit}}} del modulo {{{article}}}'' 
     642{{{ 
     643#!html 
     644<img src="http://www.symfony-project.com/images/book/trunk/F1412.png" /> 
     645}}} 
     646 
     647Dato che i titoli di default usano il nome della classe, vanno abbastanza bene (sempre che nel tuo modello tu abbia usato nomi espliciti per le classi). 
     648 
     649{{{ 
     650#!html 
     651<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/tip.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     652<p> 
     653Nelle stringhe di <code>generator.yml</code>, il valore di un campo può essere acceduto tramite il nome del campo tra %%. 
     654</p></blockquote> 
     655}}} 
     656 
     657 
     658==== Aggiungere tooltip ==== 
     659 
     660Nelle viste {{{list}}} ed {{{edit}}}, puoi aggiungere tooltip per aiutare a descrivere i campi visualizzati. Ad esempio, per aggiungere un tooltip al campo {{{article_id}}} della vista {{{edit}}} del modulo {{{comment}}}, aggiungi una prorietà {{{help}}} nella definizione {{{fields}}} come nel Listato 14-19. Il risultato è mostrato in Figura 14-13. 
     661 
     662''Listato 14-19 - Impostare un tooltip nella vista {{{edit}}}, in {{{modules/comment/config/generator.yml}}}'' 
     663{{{ 
     664#!php 
     665   edit: 
     666      fields: 
     667        ... 
     668        article_id:   { help: The current comment relates to this article } 
     669}}} 
     670 
     671''Figura 14-13 - Tooltip nella vista {{{edit}}} del modulo {{{comment}}}'' 
     672{{{ 
     673#!html 
     674<img src="http://www.symfony-project.com/images/book/trunk/F1413.png" /> 
     675}}} 
     676 
     677Nella vista {{{list}}}, i tooltip vengono visualizzati nella colonna {{{header}}}; nella vista {{{edit}}}, essi appaiono sotto l'input. 
     678 
     679 
     680==== Modificare il formato delle date ==== 
     681 
     682Le date possono nessere visualizzate secondo un formato personalizzato, se utilizzi il parametro {{{date_format}}}, come mostrato dal Listato 14-20. 
     683 
     684''Listato 14-20 - Formattare una data nella vista {{{list}}}'' 
     685{{{ 
     686#!php 
     687 list: 
     688      fields: 
     689        created_at:         { name: Published, params: date_format='dd/MM' } 
     690}}} 
     691 
     692Esso utilizza gli stessi parametri dell'helper {{{format_date()}}} visto nel capitolo precedente. 
     693 
     694{{{ 
     695#!html 
     696<blockquote class="sidebar" style="width: 800px; background-color: #cccccc;"> 
     697<p style="height: 30px; background-color: #aaaaaa; color: white; padding-top: 10px; padding-left: 10px;"><strong>Le template delle amministrazioni sono pronte per i18n</strong> 
     698<p style="margin-left: 10px;">Tutti i testi delle template generate sono internazionalizzati automaticamente (ovvero stampati tramite l'helper <code>__()</code>). Ciò significa che puoi tradurre un'amministrazione generata semplicemente inserendo i testi nel file XLIFF dentro la cartella <code>apps/myapp/i18n/</code>, come descritto nel capitolo precedente.</p> 
     699<br /> 
     700</blockquote> 
     701}}} 
     702 
     703 
     704=== Personalizzazioni specifiche per la vista list === 
     705 
     706La vista {{{list}}} può visualizzare i dettagli di un record in una tabella, oppure tutti in una linea. Inoltre contiene funzionalità di paginazione, filtri ed ordinamento. Tali funzionalità possono essere alterate tramite il file di configurazione, come illustrato nelle sezioni seguenti. 
     707 
     708 
     709==== Cambiare il layout ==== 
     710 
     711Per default, il link per passare dalla {{{list}}} alla {{{edit}}} viene inserito sulla chiave primaria. Se dai un'occhiata indietro alla Figura 14-11, vedrai che la colonna {{{id}}} non solo rappresenta la chiave primaria di ogni commento, ma è anche cliccabile per passare alla vista {{{edit}}}. 
     712 
     713Se preferisci avere tale link su un'altra colonna, metti il prefisso = su tale colonna sotto la chiave {{{display}}}. Il Listato 14-21 mostra come rimuovere la colonna {{{id}}} dalla vista {{{list}}} e mettere il link sul campo {{{content}}}. Controlla la Figura 14-14 per uno screenshot. 
     714 
     715''Listato 14-21 - Spostare il link alla vista {{{edit}}} nella vista {{{list}}}, in {{{modules/comment/config/generator.yml}}}'' 
     716{{{ 
     717#!php 
     718   list: 
     719      display:    [article_link, =content] 
     720}}} 
     721 
     722''Figura 14-14 - Spostare il link alla vista {{{edit}}} su un'altra colonna, nella vista {{{list}}} del modulo {{{comment}}}'' 
     723{{{ 
     724#!html 
     725<img src="http://www.symfony-project.com/images/book/trunk/F1414.png" /> 
     726}}} 
     727 
     728Per default, la vista {{{list}}} usa un layout tabulare, dove i campi appaiono come colonne, come visto precedentemente. Ma puoi anche usare il layout {{{stacked}}} e concatenare i campi in una singola stringa per tutta la lunghezza della tabella. Se scegli tale layout, devi impostare nella chiave {{{params}}} il pattern che definisce come la stringa deve essere composta. Ad esempio, il Listato 14-22 definisce un layout {{{stacked}}} per la vista {{{list}}} del modulo {{{comment}}}. Il risultato appare nella Figura 14-15. 
     729 
     730''Listato 14-22 - Utilizzare il layout {{{stacked}}} nella vista {{{list}}}, in {{{modules/comment/config/generator.yml}}}'' 
     731{{{ 
     732#!php 
     733 list: 
     734      layout:  stacked 
     735      params:  | 
     736        %%=content%% <br /> 
     737        (sent by %%author%% on %%created_at%% about %%article_link%%) 
     738      display:  [created_at, author, content] 
     739}}} 
     740 
     741''Figura 14-15 - Layout {{{stacked}}} per la vista {{{list}}} del modulo {{{comment}}}'' 
     742{{{ 
     743#!html 
     744<img src="http://www.symfony-project.com/images/book/trunk/F1415.png" /> 
     745}}} 
     746 
     747Nota che il layout {{{tabular}}} si aspetta un array di campi sotto la chiave {{{display}}}, ma quello {{{stacked}}} usa la chiave {{{params}}} per il codice HTML per ogni record generato. Comunque, l'array {{{display}}} è usato nel layout {{{stacked}}} per determinare quali colonne sono disponibili per l'ordinamento interattivo. 
     748 
     749 
     750==== Filtrare i risultati ==== 
     751 
     752Nella vista {{{list}}} puoi aggiungere un insieme di interazioni per i filtri. Tramite essi, l'utente può visualizzare meno risultati e trovare così quelli che cerca più velocemente. Configura il filtri sotto la chiave {{{filters}}}, con un array di nomi di campi. Ad esempio, per avere un risultato come quello della Figura 14-16, aggiungi un filtro sui campi {{{article_id}}}, {{{author}}} e {{{created_at}}}, come mostrato nel Listato 14-23. Per fare ciò, avrai anche bisogno di aggiungere un metodo {{{__toString()}}} alla classe {{{Article}}} (che restituisca, ad esempio, il titolo dell'articolo). 
     753 
     754''Listato 14-23 - Impostare filtri nella vista {{{list}}}, in {{{modules/comment/config/generator.yml}}}'' 
     755{{{ 
     756#!php 
     757 list: 
     758      filters: [article_id, author, created_at] 
     759      layout:  stacked 
     760      params:  | 
     761        %%=content%% <br /> 
     762        (sent by %%author%% on %%created_at%% about %%article_link%%) 
     763      display:  [created_at, author, content] 
     764}}} 
     765 
     766''Figura 14-16 - Filtri nella vista {{{list}}} del modulo {{{comment}}}'' 
     767{{{ 
     768#!html 
     769<img src="http://www.symfony-project.com/images/book/trunk/F1416.png" /> 
     770}}} 
     771 
     772I filtri visualizzati da symfony dipendono dal tipo di colonna: 
     773 * Per colonne di testo (come il campo {{{author}}} del modulo {{{comment}}}), il filtro è una casella di testo che permette ricerche con wildcard (*). 
     774 * Per le chiavi importate (come il campo {{{article_id}}} del modulo {{{comment}}}), il filtro è un menu a tendina con i record della tabella relativa. Come per l'helper {{{object_select_tag()}}}, le options del menu a tendina sono le stringhe restituite dal metodo {{{__toString()}}} della classe relativa. 
     775 * Per le date (come il campo {{{created_at}}} del modulo {{{comment}}}), il filtro è una coppia di tag date rich (casella di testo e widget calendario) che permettono la selezione di intervalli di tempo. 
     776 * Per colonne boolane, il filtro è un menu a tendina con le opzioni {{{true}}}, {{{false}}} e {{{true or false}}} (quest'ultimo valore reinizializza il filtro). 
     777 
     778Esattamente come usi campi partial nelle liste, puoi creare filtri partial per averne un non gestito automaticamente da symfony. Ad esempio, immagina un campo {{{state}}} che possa contenere solo due valori ({{{open}}} e {{{closed}}}), ma per qualche ragione memorizzi il valore direttamente nel campo invece che in una tabella. Un semplice filtro su questo campo (di tipo {{{string}}}) sarebbe una ricerca di testo, ma probabilmente tu vorresti un menu a tendina. Questo diventa semplice da realizzare con un filtro partial. Vedi il Listato 14-24 per un esempio di implementazione. 
     779 
     780''Listato 14-24 - Utilizzare un filtro partial'' 
     781{{{ 
     782#!php 
     783// Definizione del partial, in templates/_state.php 
     784<?php echo select_tag('filters[state]', options_for_select(array( 
     785  '' => '', 
     786  'open' => 'open', 
     787  'closed' => 'closed', 
     788), isset($filters['state']) ? $filters['state'] : '')) ?> 
     789  
     790// Aggiunta del partial nella lista dei filtri, in config/generator.yml 
     791    list: 
     792      filters:        [date, _state] 
     793}}} 
     794 
     795Nota che il partial ha accesso alla variabile {{{$filters}}}, utile per recuperare il valore corrente del filtro. 
     796 
     797C'è un'ultima opzione che può essere molto utile nella ricerca di valori vuoti. Immagina di voler filtrare la lista dei commenti per visualizzare solo quelli senza autore. Il problema è che se lasci il filtro author vuoto, verrà semplicemente ignorato. La soluzione è impostare il campo {{{filter_is_empty}}} a {{{true}}}, come nel listato 14-25, ed il filtro mostrerà un checkbox addizionale che ti permetterà di cercare valori vuoti, come mostrato in Figura 14-17. 
     798 
     799''Listato 14-25 - Aggiungere un filtro per valori vuoti sul campo {{{author}}} nella vista {{{list}}}'' 
     800{{{ 
     801#!php 
     802list: 
     803      fields: 
     804        author:   { filter_is_empty: true } 
     805      filters:    [article_id, author, created_at] 
     806}}} 
     807 
     808''Figura 14-17 - Permettere il filtro di valori vuoti'' 
     809{{{ 
     810#!html 
     811<img src="http://www.symfony-project.com/images/book/trunk/F1417.png" /> 
     812}}} 
     813 
     814 
     815==== Ordinamento della lista ==== 
     816 
     817Nella vista {{{list}}}, gli header della tabella sono link che possono essere usati per riordinare la lista, come mostrato in Figura 14-18. Tali header vengono mostrati in entrambi i layout, {{{tabular}}} e {{{stacked}}}. Cliccarne uno significa ricaricare la pagina con un parametro {{{sort}}} che ordina la lista di conseguenza. 
     818 
     819''Figura 14-18 - Gli header nella tabella della vista {{{list}}} controllano l'ordinamento'' 
     820{{{ 
     821#!html 
     822<img src="http://www.symfony-project.com/images/book/trunk/F1418.png" /> 
     823}}} 
     824 
     825Puoi riutilizzare la sintassi per indirizzare un'elenco già ordinato secondo una colonna: 
     826 
     827{{{ 
     828#!php 
     829<?php echo link_to('Comment list by date', 'comment/list?sort=created_at&type=desc' ) ?> 
     830}}} 
     831 
     832Puoi infine definire un ordinamento di default direttamente nel file di configurazione {{{generator.yml}}}. La sintassi è mostrata nell'esempio del Listato 14-26. 
     833 
     834''Listato 14-26 - Impostare un ordinamento di default nella vista {{{list}}}'' 
     835{{{ 
     836#!php 
     837    list: 
     838      sort:   created_at 
     839      # Sintassi alternativa, per specificare un ordine 
     840      sort:   [created_at, desc] 
     841}}} 
     842 
     843{{{ 
     844#!html 
     845<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/note.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     846<p> 
     847Solo i campi corrispondenti a colonne effettive sono trasformati in controlli di ordinamento, non i partial od i campi personalizzati. 
     848</p></blockquote> 
     849}}} 
     850 
     851 
     852==== Personalizzare la paginazione ==== 
     853 
     854Le amministrazioni generate gestiscono bene anche tabelle molto grandi, perchè per default utilizzano la paginazione. Quando il numero effettivo di righe eccede il numero massimo di righe per pagina, i controlli della paginazione appaiono nell'angolo in basso a destra. Ad esempio, la Figura 14-19 mostra la lista dei commenti con sei commenti di test nella tabella ma un limite di cinque per pagina. La paginazione assicura buone prestazioni, in quanto solo le righe da visualizzare sono effettivamente recuperate dal database, ed una buona usabilità, perchè anche tabelle con milioni di righe possono essere gestite da un modulo di amministrazione. 
     855 
     856''Figura 14-19 - Appaiono i controlli di paginazione in elenchi lunghi'' 
     857{{{ 
     858#!html 
     859<img src="http://www.symfony-project.com/images/book/trunk/F1419.png" /> 
     860}}} 
     861 
     862Puoi personalizzare il numero di record da visualizzare per pagina tramite il parametro {{{max_per_page}}}: 
     863 
     864{{{ 
     865#!php 
     866 list: 
     867      max_per_page:   5 
     868}}} 
     869 
     870 
     871==== Usare un join per velocizzare la spedizione delle pagine ==== 
     872 
     873Per default, un generatore di administration usa una semplice {{{doSelect()}}} per recuperare una lista di record dal db. Ma se gli oggetti della lista hanno delle relazioni, il numero di query necessarie alla sua costruzione potrebbe aumentare velocemente. Ad esempio, se vuoi vedere il nome dell'articolo in una lista di commenti, necessaria una query addizionale per ogni record per trovare il relativo {{{Article}}}. Per cui potresti voler forzare il pager ad utilizzare il metodo {{{doSelectJoinXXX()}}} per ottimizzare il numero di query. Ciò può essere specificato tramite il parametro {{{peer_method}}}. 
     874 
     875{{{ 
     876#!php 
     877list: 
     878      peer_method:   doSelectJoinArticle 
     879}}} 
     880 
     881Il Capitolo 18 spiega più estensivamente il concetto di join. 
     882 
     883 
     884=== Personalizzazioni specifiche per la vista edit === 
     885 
     886Nella vista {{{edit}}}, l'utente può modificare il valore di ogni colonna per un dato record. Symfony determina il tipo di input da visualizzare secondo il data type della colonna. Quindi genera un helper {{{object_*_tag()}}}, e gli passa l'oggetto e la proprietà da modificare. Ad esempio, se nella configurazione della vista {{{edit}}} per l'articolo è specificato che l'utente può modificare il campo {{{title}}}: 
     887 
     888{{{ 
     889#!php 
     890edit: 
     891      display: [title, ...] 
     892}}} 
     893 
     894allora nella pagina {{{edit}}} verrà visualizzato una casella di testo per la modifica di {{{title}}}, in quanto nello schema esso è definito di tipo {{{varchar}}}. 
     895 
     896{{{ 
     897#!php 
     898<?php echo object_input_tag($article, 'getTitle') ?> 
     899}}} 
     900 
     901 
     902==== Cambiare il tipo di input ==== 
     903 
     904Le regole di conversione type-to-field di default sono le seguenti: 
     905 * Una colonna definita come {{{integer, float, char, varchar(size)}}} appare nella vista {{{edit}}} come un {{{object_input_tag()}}}. 
     906 * Una colonna definita come {{{longvarchar}}} appare come {{{object_textarea_tag()}}}. 
     907 * Una chiave importata appare come {{{object_select_tag()}}}. 
     908 * Una colonna definita come {{{boolean}}} appare come {{{object_checkbox_tag()}}}. 
     909 * Una colonna definita come {{{timestamp}}} appare come {{{object_input_date_tag()}}}. 
     910 
     911Potresti voler fare l'override di queste regole per specificare un tipo di input personalizzato per un certo campo. Per fare ciò, imposta il parametro {{{type}}} ad uno specifico nome di helper nella definizione {{{fields}}}. Come per le opzioni del {{{object_*_tag()}}} generato, le puoi cambiare tramite il parametro {{{params}}}. Un esempio nel Listato 14-27. 
     912 
     913''Listato 14-27 - Impostare un tipo di input personalizzato per la vista {{{edit}}}'' 
     914{{{ 
     915#!php 
     916generator: 
     917  class:              sfPropelAdminGenerator 
     918  param: 
     919    model_class:      Comment 
     920    theme:            default 
     921 
     922    edit: 
     923      fields: 
     924                      ## Drop the input, just display plain text 
     925        id:           { type: plain } 
     926                      ## The input is not editable 
     927        author:       { params: disabled=true } 
     928                      ## The input is a textarea (object_textarea_tag) 
     929        content:      { type: textarea_tag, params: rich=true css=user.css tinymce_options=width:330 } 
     930                      ## The input is a select (object_select_tag) 
     931        article_id:   { params: include_custom=Choose an article } 
     932         ... 
     933}}} 
     934 
     935I parametri {{{params}}} vengono passati come opzioni al {{{object_*_tag()}}} generato. Ad esempio, la definizione di {{{params}}} per il precedente {{{article_id}}} produce nella template: 
     936 
     937{{{ 
     938#!php 
     939<?php echo object_select_tag($comment, 'getArticleId', 'related_class=Article', 'include_custom=Choose an article') ?> 
     940}}} 
     941 
     942Ciò significa che tutte le opzioni normalmente disponibili negli helper delle form possono essere personalizzate nella vista {{{edit}}}. 
     943 
     944 
     945==== Gestire campi partial ==== 
     946 
     947I campi partial possono essere usati nella vista {{{edit}}} proprio come nella {{{list}}}. La differenza sta nel fatto che devi gestire manualmente, nell'azione, l'aggiornamento della colonna secondo il valore del parametro di richiesta spedito dal partial. Symfony sa come gestire i campi normali (corrispondenti alle colonne effettive), ma non può immaginare come gestire input che tu potresti inserire in partial. 
     948 
     949Ad esempio, immagina un modulo di amministrazione per una classe {{{User}}} dove sono disponibili i campi {{{id, nickname}}}, e {{{password}}}. L'amministratore del sito deve poter cambiare la password di un utente ma la vista {{{edit}}} non deve visualizzarne il valore per motivi di sicurezza. Invece, la form deve mostrare una casella di testo vuota che l'amministratore può riempire per cambiare la password. Le impostazioni per il generatore per tale tipo di vista sono simili a quelli del Listato 14-28. 
     950 
     951''Listato 14-28 - Includere un partial nella lista {{{edit}}}'' 
     952{{{ 
     953#!php 
     954   edit: 
     955      display:        [id, nickname, _newpassword] 
     956      fields: 
     957        newpassword:  { name: Password, help: Enter a password to change it, leave the field blank to keep the current one } 
     958}}} 
     959 
     960Il partial {{{templates/_newpassword.php}}} contiente qualcosa tipo 
     961 
     962{{{ 
     963#!php 
     964<?php echo input_password_tag('newpassword', '') ?> 
     965}}} 
     966 
     967Nota che questo partial utilizza un helper delle form normale, non un object, in quanto non è desiderabile recuperare il valore della password dall'oggetto {{{User}}} corrente per popolare una casella di testo.  
     968 
     969Ora, per utilizzare il valore di tale input per poter aggiornare l'oggetto nell'azione, ne devi estendere il metodo {{{updateUserFromRequest()}}}. Per fare ciò, crea un metodo con lo stesso nome nella classe dell'azione, come mostrato nel Listato 14-29. 
     970 
     971''Listato 14-29 - Gestire un partial nell'azione, in {{{modules/user/actions/actions.class.php}}}'' 
     972{{{ 
     973#!php 
     974class userActions extends sfActions 
     975{ 
     976  protected function updateUserFromRequest() 
     977  { 
     978    // Handle the input of the partial field 
     979    $password = $this->getRequestParameter('newpassword'); 
     980  
     981    if ($password) 
     982    { 
     983      $this->user->setPassword($password); 
     984    } 
     985  
     986    // Let symfony handle the other fields 
     987    parent::updateUserFromRequest(); 
     988  } 
     989} 
     990}}} 
     991 
     992{{{ 
     993#!html 
     994<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/note.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     995<p> 
     996Nel mondo reale, una vista <code>user/edit</code> contiene due campi per la password, il secondo dei quali deve contenere lo stesso valore del primo per controllare che non ci siano errori di digitazione. In pratica, come hai visto nel Capitolo 10, questo viene fatto tramite validazione. Le amministrazioni generate beneficiano dello stesso meccanismo come gli altri moduli. 
     997</p></blockquote> 
     998}}} 
     999 
     1000 
     1001=== Gestire chiavi importate === 
     1002 
     1003Se il tuo schema definisce relazioni tra le tabelle, i moduli di amministrazione generati se ne avvantaggiano offrendo controlli automatizzati, semplificando così enormemente il sistema di gestione delle relazioni. 
     1004 
     1005 
     1006==== Relazioni uno-a-molti ==== 
     1007 
     1008Il generatore di amministrazioni si occupa di relazioni 1-n. Come illustrato precedentemente nella Figura 14-1, la tabella {{{blog_comment}}} legata a {{{blog_article}}} tramite il campo {{{article_id}}}. Se inizializzi il modulo della classe {{{Comment}}} con il generatore di amministrazioni, l'azione {{{comment/edit}}} visualizzerà automaticamente {{{article_id}}} come un menu a tendina con gli ID dei record disponibili della tabella {{{blog_article}}} (controlla di nuovo la Figura 14-9 per un esempio). 
     1009 
     1010Inoltre, se definisci un metodo {{{__toString()}}} nell'oggetto {{{Article}}}, la tendina mostrerà nelle proprie opzioni invece delle chiavi primarie il valore restituito da tale metodo. 
     1011 
     1012Se hai bisogno di mostrare la lista dei commenti relativi ad un articolo nel modulo {{{article}}} (relazione n-1), avrai bisogno di personalizzare un pochino il modulo tramite un partial. 
     1013 
     1014 
     1015=== Relazioni molti-a-molti ==== 
     1016 
     1017Symfony si occupa anche delle relazioni n-n, ma dato che non le puoi definire nello schema, devi aggiungere qualche parametro nel file {{{generator.yml}}}. 
     1018 
     1019L'implementazione delle relazioni n-n richiede una tabella intermedia. Se ad esempio ci fosse una relazione n-n fra le tabelle {{{blog_article}}} e {{{blog_author}}} (un articolo può essere scritto da più di un autore e, ovviamente, un autore può scrivere più articoli), il tuo database avrà una tabella {{{blog_article_author}}} o simile, come mostrato in Figura 14-20. 
     1020 
     1021''Figura 14-20 - Implementazione delle relazioni molti-a-molti'' 
     1022{{{ 
     1023#!html 
     1024<img src="http://www.symfony-project.com/images/book/trunk/F1420.png" /> 
     1025}}} 
     1026 
     1027Il modello avrà quindi una classe chiamata {{{ArticleAuthor}}}, e questa è la sola cosa di cui il generatore di amministrazioni abbia bisogno; ma devi passarglielo come parametro {{{through_class}}}. 
     1028 
     1029Ad esempio, in un modulo generato basato sulla classe {{{Article}}}, puoi aggiungere un campo per creare una relazione n-n con la classe {{{Author}}} se scrivi il file {{{generator.yml}}} come nel Listato 14-30. 
     1030 
     1031''Listato 14-30 - Gestire relazioni molti-a-molti tramite il parametro {{{through_class}}}'' 
     1032{{{ 
     1033#!php 
     1034edit: 
     1035      fields: 
     1036        article_author: { type: admin_double_list, params: through_class=ArticleAuthor } 
     1037}}} 
     1038 
     1039Tale campo gestisce i collegamenti tra gli oggetti esistenti, per cui un menu a tendina non è sufficiente. Devi usare un tipo di input speciale in questo caso. 
     1040Symfony offre tre widget per aiutare a mettere in relazione i membri di due liste (illustrati nella Figura 14-21): 
     1041 * Un {{{admin_double_list}}} è un insieme di due menu a tendina espansi, entrambi con pulsanti per spostare elementi dalla prima lista (disponibili) alla seconda (selezionati). 
     1042 * Un {{{admin_select_list}}} è un menu a tendina multiplo, in cui puoi selezionare più di un elemento. 
     1043 * Un {{{admin_check_list}}} è una lista di checkbox. 
     1044 
     1045''Figura 14-21 - Controlli disponibili per relazioni molti-a-molti'' 
     1046{{{ 
     1047#!html 
     1048<img src="http://www.symfony-project.com/images/book/trunk/F1421.png" /> 
     1049}}} 
     1050 
     1051 
     1052=== Aggiungere interazioni === 
     1053 
     1054I moduli di amministrazione permettono le normali operazioni CRUD, ma puoi anche aggiungere le tue personali interazioni o limitazioni. Ad esempio, l'interazione definita nel Listato 14-31 fornisce accesso a tutte le azioni CRUD di default sul modulo {{{article}}}. 
     1055 
     1056''Listato 14-31 - Definire interazioni per ogni vista, in {{{backend/modules/article/config/generator.yml}}}'' 
     1057{{{ 
     1058#!php 
     1059  list: 
     1060      title:          List of Articles 
     1061      object_actions: 
     1062        _edit:         ~ 
     1063        _delete:       ~ 
     1064      actions: 
     1065        _create:       ~ 
     1066 
     1067    edit: 
     1068      title:          Body of article %%title%% 
     1069      actions: 
     1070        _list:         ~ 
     1071        _save:         ~ 
     1072        _save_and_add: ~ 
     1073        _delete:       ~ 
     1074}}} 
     1075 
     1076In una vista {{{list}}} ci sono due impostazioni di azione: la lista delle azioni disponibili per ogni oggetto, e quelle per l'intera pagina. L'effetto delle interazioni definite nel Listato 14-31 è mostrato in Figura 14-22. Ogni linea mostra un pulsante per modificare il record ed uno per eliminarlo. Alla ifne della pagina, un pulsante permette di crearne di nuovi. 
     1077 
     1078''Figura 14-22 - Interazioni nella vista {{{list}}}'' 
     1079{{{ 
     1080#!html 
     1081<img src="http://www.symfony-project.com/images/book/trunk/F1422.png" /> 
     1082}}} 
     1083 
     1084In una vista {{{edit}}}, dato che c'è un solo record da modificare, è disponibile un solo set di azioni da definire. L'effetto delle interazioni {{{edit}}} definite nel Listato 14-31 è mostrato in Figura 14-23. Entrambe le azioni {{{save}}} e {{{save_and_add}}} salvano il record corrente; a differenza è che la prima mostra i dati salvati, la seconda campi vuoti per aggiungere un nuovo record. Tale azione risulterà molto utile quando devi aggiungere molti record in rapida successione. Riguardo la posizione del pulsante {{{delete}}}, esso è distanziato dagli altri perchè non venga cliccato per errore. 
     1085 
     1086I nomi delle interazioni che cominciano con un underscore (_) indicano a symfony di usare le icone ed azioni di default corrispondenti; il generatore di amministrazioni capisce {{{_edit, _delete, _create, _list, _save, _save_and_add}}}, e {{{_create}}}. 
     1087 
     1088''Figura 14-23 - Interazioni nella vista {{{edit}}}'' 
     1089{{{ 
     1090#!html 
     1091<img src="http://www.symfony-project.com/images/book/trunk/F1423.png" /> 
     1092}}} 
     1093 
     1094Ma puoi anche aggiungere un'interazione personalizzata, nel qual caso devi specificare un nome che non cominci con underscore, come nel Listato 14-32. 
     1095 
     1096''Listato 14-32 - Definire un'interazione personalizzata'' 
     1097{{{ 
     1098#!php 
     1099list: 
     1100      title:          List of Articles 
     1101      object_actions: 
     1102        _edit:        - 
     1103        _delete:      - 
     1104        addcomment:   { name: Add a comment, action: addComment, icon: backend/addcomment.png } 
     1105}}} 
     1106 
     1107Ogni articolo della lista visualizzerà ora un pulsante {{{addcomment.png}}}, come mostrato in Figura 14-24. Cliccandolo viene chiamata l'azione {{{addComment}}} del modulo corrente. La chiave primaria dell'oggetto corrente viene aggiunta automaticamente ai parametri di richiesta. 
     1108 
     1109''Figura 14-24 - Interazione personalizzata nella vista {{{list}}}'' 
     1110{{{ 
     1111#!html 
     1112<img src="http://www.symfony-project.com/images/book/trunk/F1424.png" /> 
     1113}}} 
     1114 
     1115L'azione {{{addComment}}} può essere implementata come nel Listato 14-33. 
     1116 
     1117''Listato 14-33 - Implementare l'azione dell'interazione personalizzata, in {{{actions/actions.class.php}}}'' 
     1118{{{ 
     1119#!php 
     1120public function executeAddComment() 
     1121{ 
     1122  $comment = new Comment(); 
     1123  $comment->setArticleId($this->getRequestParameter('id')); 
     1124  $comment->save(); 
     1125  
     1126  $this->redirect('comment/edit?id='.$comment->getId()); 
     1127} 
     1128}}} 
     1129 
     1130Un'ultima cosa a proposito delle azioni: se vuoi sopprimere completamente le azioni per una categoria, usa una lista vuota, come nel Listato 14-34. 
     1131 
     1132''Listato 14-34 - Rimuovere tutte le azioni nella vista {{{list}}}'' 
     1133{{{ 
     1134#!php 
     1135list: 
     1136      title:          List of Articles 
     1137      actions:        {} 
     1138}}} 
     1139 
     1140 
     1141=== Validazione delle form === 
     1142 
     1143Se dai un'occhiata alla template generata {{{_edit_form.php}}} nella cartella {{{cache/}}} del tuo progetto, vedrai che i nomi dei campi della form usano una convenzione speciale. In una vista {{{edit}}} generata, i nomi dei campi sono la concatenazione del nome del modulo e del campo tra parentesi quadre. 
     1144 
     1145Ad esempio, se la vista {{{edit}}} per il modulo {{{article}}} ha un campo {{{title}}}, la template sarà come quella del Listato 14-35 ed il campo sarà identificato come {{{article[title]}}}. 
     1146 
     1147''Listato 14-35 - Sintassi dei nomi degli input generati'' 
     1148{{{ 
     1149#!php 
     1150// generator.yml 
     1151generator: 
     1152  class:              sfPropelAdminGenerator 
     1153  param: 
     1154    model_class:      Article 
     1155    theme:            default 
     1156    edit: 
     1157      display: [title] 
     1158 
     1159// Resulting _edit_form.php template 
     1160<?php echo object_input_tag($article, 'getTitle', array('control_name' => 'article[title]')) ?> 
     1161 
     1162// Resulting HTML 
     1163<input type="text" name="article[title]" id="article[title]" value="My Title" /> 
     1164}}} 
     1165 
     1166Ciò ha molti vantaggi durante il processo di gestione interna della form. Come spiegato nel Capitolo 10, ciò ha anche come conseguenza l'aggiunta di un pizzico di complessità nella configurazione della validazione, per cui devi sostituire le parentesi quadre con le graffe nella definizione {{{fields}}}. Inoltre, quando usi il nome di un campo come parametro per la validazione, lo devi specificare come appare nel codice HTML generato (ovvero con le parentesi quadre ma tra doppi apici). Consulta il Listato 14-36 per dettagli sulla sintassi speciale della validazione per form generate. 
     1167 
     1168''Listato 14-36 - Sintassi per la validazione di form generate nelle amministrazioni'' 
     1169{{{ 
     1170#!php 
     1171## Sostituzione delle parentesi quadre con le graffe nella definizione fields 
     1172fields: 
     1173  article{title}: 
     1174    required: 
     1175      msg: You must provide a title 
     1176    ## Per i parametri di validazione usa i doppi apici 
     1177    sfCompareValidator: 
     1178      check:        "user[newpassword]" 
     1179      compare_error: The password confirmation does not match the password. 
     1180}}} 
     1181 
     1182 
     1183=== Limitare le azioni dell'utente utilizzando credenziali === 
     1184 
     1185Per un dato modulo di amministrazione, i campi disponibili e le interazioni possono variare a seconda delle credenziali dell'utente corrente (consulta il Capitolo 6 per una descrizione delle funzionalità di sicurezza di symfony). 
     1186 
     1187I campi nel generatore possono avere un parametro {{{credentials}}} in modo da apparire solo agli utenti che hanno le credenziali corrette. Ciò funziona per le viste {{{list}}} ed {{{edit}}}. Inoltre, il generatore può anche nascondere interazioni secondo le credenziali. Il Listato 14-37 mostra tali funzionalità. 
     1188 
     1189''Listato 14-37 - Utilizzo delle credenziali in {{{generator.yml}}}'' 
     1190{{{ 
     1191#!php 
     1192## La colonna id viene mostrata solo ad utenti con credenziali admin 
     1193    list: 
     1194      title:          List of Articles 
     1195      layout:         tabular 
     1196      display:        [id, =title, content, nb_comments] 
     1197      fields: 
     1198        id:           { credentials: [admin] } 
     1199 
     1200## L'interazione addcomment è limitata agli utenti con credenziali admin 
     1201    list: 
     1202      title:          List of Articles 
     1203      object_actions: 
     1204        _edit:        - 
     1205        _delete:      - 
     1206        addcomment:   { credentials: [admin], name: Add a comment, action: addComment, icon: backend/addcomment.png } 
     1207}}} 
     1208 
     1209 
     1210== Modificare la presentazione dei moduli generati == 
     1211 
     1212Puoi modificare la presentazione dei moduli generati in modo che rispetti lo stile dell'applicazione, non solo applicando il tuo stylesheet ma anche facendo l'override delle template di default. 
     1213 
     1214 
     1215=== Utilizzare un foglio di stile personalizzato === 
     1216 
     1217Dato che l'HTML generato è contenuto strutturato, puoi fare ciò che ti piace con la presentazione. 
     1218 
     1219Puoi definire un CSS alternativo da usare con un modulo di amministrazione al posto di quello di default aggiungendo un parametro {{{css}}} alla configurazione del generatore, come mostrato nel Listato 14-38. 
     1220 
     1221''Listato 14-38 - Usare uno stylesheet personalizzato invece di quello di default'' 
     1222{{{ 
     1223#!php 
     1224generator: 
     1225  class:              sfPropelAdminGenerator 
     1226  param: 
     1227    model_class:      Comment 
     1228    theme:            default 
     1229    css:              mystylesheet 
     1230}}} 
     1231 
     1232Alternativamente puoi usare i meccanismi forniti dal modulo {{{view.yml}}} per fare l'override degli stili per ogni vista. 
     1233 
     1234 
     1235=== Creare un header ed un footer personalizzati === 
     1236 
     1237Le viste {{{list}}} ed {{{edit}}} includono sistematicamente partial per l'header ed il footer. Per default non c'è alcun partial nella cartella {{{templates/}}} di un modulo di amministrazione, ma per averlo incluso automaticamente ne devi semplicemente aggiungere uno con uno dei seguenti nomi: 
     1238 
     1239{{{ 
     1240#!php 
     1241_list_header.php 
     1242_list_footer.php 
     1243_edit_header.php 
     1244_edit_footer.php 
     1245}}} 
     1246 
     1247Ad esempio, se vuoi aggiungere un header personalizzato per la vista {{{article/edit}}}, crea un file chiamato {{{_edit_header.php}}} come nel Listato 14-39. Funzionerà senza ulteriori configurazioni. 
     1248 
     1249''Listato 14-39 - Esempio di header partial {{{edit}}}, in {{{modules/articles/template/_edit_header.php}}}'' 
     1250{{{ 
     1251#!php 
     1252<?php if ($article->getNbComments() > 0): ?> 
     1253  <h2>This article has <?php echo $article->getNbComments() ?> comments.</h2> 
     1254<?php endif; ?> 
     1255}}} 
     1256 
     1257Nota che un partial {{{edit}}} ha sempre accesso all'oggetto corrente tramite una variabile con lo stesso nome del modulo, e che un partial {{{list}}} ha sempre accesso al pager corrente tramite la variabile {{{$pager}}}. 
     1258 
     1259{{{ 
     1260#!html 
     1261<blockquote class="sidebar" style="width: 800px; background-color: #cccccc;"> 
     1262<p style="height: 30px; background-color: #aaaaaa; color: white; padding-top: 10px; padding-left: 10px;"><strong>Chiamare le azioni dell'amministrazione tramite parametri personalizzati</strong> 
     1263<p style="margin-left: 10px;">Le azioni del modulo di amministrazione possono ricevere parametri personalizzati utilizzando l'argomento <code>query_string</code> nell'helper <code>link_to()</code>. Ad esempio, per esterndere il partial precedente <code>_edit_header</code> con un link ai commenti di un articolo, scrivi:</p> 
     1264<code> 
     1265}}} 
     1266{{{ 
     1267#!php 
     1268<?php if ($article->getNbComments() > 0): ?> 
     1269<a name="This article has <?php echo link_to($article->getNbComments().' comments', 'comment/list', array('query_string' => 'filter=filter&filters%5Barticle_id%5D='.$article->getId())) ?>"></a><h2>This article has <?php echo link_to($article->getNbComments().' comments', 'comment/list', array('query_string' => 'filter=filter&filters%5Barticle_id%5D='.$article->getId())) ?></h2> 
     1270<?php endif; ?> 
     1271}}} 
     1272{{{ 
     1273#!html 
     1274</code> 
     1275<p style="margin-left: 10px;">Per una versione più leggibile:</p> 
     1276<code> 
     1277}}} 
     1278{{{ 
     1279#!php 
     1280'filter=filter&filters[article_id]='.$article->getId() 
     1281}}} 
     1282{{{ 
     1283#!html 
     1284</code> 
     1285<p style="margin-left: 10px;">Esso filtra i commenti per visualizzare solo quelli relativi a <code>$article</code>. Usando l'argomento query_string, puoi specificare un ordinamento e/o un filtro per viste personalizzate.</p> 
     1286<br /> 
     1287</blockquote> 
     1288}}} 
     1289 
     1290 
     1291=== Personalizzare il tema === 
     1292 
     1293Ci sono altri partial ereditati dal framework di cui puoi fare l'override nella cartella {{{templates/}}} del modulo perchè rispondano alle tue esigenze. 
     1294 
     1295Le template del generatore sono divise in piccole parti che possono essere overridate indipendentemente, ed anche le azioni possono essere cambiate ad una ad una. 
     1296 
     1297Comunque, se ne volessi fare l'override per diversi moduli nello stesso modo, dovresti probabilmente creare un tema. Si tratta di un set completo di template ed azioni che possono essere usate in un modulo di amministrazione se specificato nel valore {{{theme}}} all'inizio del file {{{generator.yml}}}. Con il tema di default, symfony usa i file definiti in {{{$sf_symfony_data_dir/generator/sfPropelAdmin/default/}}}. 
     1298 
     1299I file del tema devono essere situati in una struttura ad albero del progetto, nella cartella {{{data/generator/sfPropelAdmin/[theme_name]/template/}}}, e potresti iniziare un nuovo tema copiando i file di quello di default (situati in {{{$sf_symfony_data_dir/generator/sfPropelAdmin/default/template/}}}). In questo modo, sei sicuro che tutti i file necessari ad un tema saranno presenti: 
     1300 
     1301{{{ 
     1302#!php 
     1303// Partials, in [theme_name]/template/templates/ 
     1304_edit_actions.php 
     1305_edit_footer.php 
     1306_edit_form.php 
     1307_edit_header.php 
     1308_edit_messages.php 
     1309_filters.php 
     1310_list.php 
     1311_list_actions.php 
     1312_list_footer.php 
     1313_list_header.php 
     1314_list_messages.php 
     1315_list_td_actions.php 
     1316_list_td_stacked.php 
     1317_list_td_tabular.php 
     1318_list_th_stacked.php 
     1319_list_th_tabular.php 
     1320 
     1321// Actions, in [theme_name]/template/actions/actions.class.php 
     1322processFilters()     // Process the request filters 
     1323addFiltersCriteria() // Adds a filter to the Criteria object 
     1324processSort() 
     1325addSortCriteria() 
     1326}}} 
     1327 
     1328Stai attento al fatto che le template in effetti sono template di template, ovvero file PHP di cui verrà fatto il parsing tramite una utility speciale per generare le template secondo le impostazioni del generatore (questa viene chiamata fase di compilazione). Le template generate devono ancora contenere codice PHP da eseguire durante il browsing effettivo, per cui le template di template usano una sintassi alternativa per mantenere il codice PHP non eseguibile al primo passo. Il Listato 14-40 mostra un estratto di una template di template di default. 
     1329 
     1330''Listato 14-40 - Sintassi di template di template'' 
     1331{{{ 
     1332#!php 
     1333<?php foreach ($this->getPrimaryKey() as $pk): ?> 
     1334[?php echo object_input_hidden_tag($<?php echo $this->getSingularName() ?>,'get<?php echo $pk->getPhpName() ?>') ?] 
     1335<?php endforeach; ?> 
     1336}}} 
     1337 
     1338In questo listato, il codice PHP introdotto da <?  eseguito immediatamente (in compilazione), quello che comincia con [? viene solo eseguito in esecuzione, ma il template engine trasforma infine i tag in modo che la template finale risulta: 
     1339 
     1340{{{ 
     1341#!php 
     1342<?php echo object_input_hidden_tag($article, 'getId') ?> 
     1343}}} 
     1344 
     1345Gestire template di template è difficoltoso, per cui se vuoi creare il tuo tema il consiglio migliore è quello di partire da quello di default e modificarlo passo passo, e testarlo estensivamente. 
     1346 
     1347{{{ 
     1348#!html 
     1349<blockquote style="padding: 5px 20px 5px 40px; margin: 10px 0; background: #ffc url(http://www.symfony-project.com/images/tip.gif) no-repeat 5px 10px; border: 1px solid #ddd;"> 
     1350<p> 
     1351Puoi anche pacchettizzare un tema in un plugin, che lo rende più riutilizzabile e facile da distribuire su più applicazioni. Consulta il Capitolo 17 per maggiori informazioni. 
     1352</p></blockquote> 
     1353}}} 
     1354 
     1355{{{ 
     1356#!html 
     1357<blockquote class="sidebar" style="width: 800px; background-color: #cccccc;"> 
     1358<p style="height: 30px; background-color: #aaaaaa; color: white; padding-top: 10px; padding-left: 10px;"><strong>Costruire il tuo generatore</strong> 
     1359<p style="margin-left: 10px;">I generatori di scaffolding ed amministrazione usano entrambi un set di componenti interni di symfony che automatizzano la creazione di azioni e template generate nella cache, l'utilizzo dei temi, ed il parsing di template di template.<br /><br />Ciò significa che symfony fornisce tutti gli strumenti per costruire il tuo proprio generatore, che può essere come quello esistente o completamente differente. La generazione di un modulo è gestita dal metodo <code>generate()</code> della classe <code>sfGeneratorManager</code>. Ad esempio, per generare una amministrazione, symfony chiama internamente:</p> 
     1360<code> 
     1361}}} 
     1362{{{ 
     1363#!php 
     1364$generator_manager = new sfGeneratorManager(); 
     1365$data = $generator_manager->generate('sfPropelAdminGenerator', $parameters); 
     1366}}} 
     1367{{{ 
     1368#!html 
     1369</code> 
     1370   
     1371<p style="margin-left: 10px;">Se vuoi costruire il tuo generatore, dovresti guardare le API per le classi <code>sfGeneratorManager</code> e <code>sfGenerator</code>, ed usare come esempi le classi <code>sfAdminGenerator</code> e <code>sfCRUDGenerator</code>. 
     1372</p><br /> 
     1373</blockquote> 
     1374}}} 
     1375 
     1376 
     1377== Sommario == 
     1378 
     1379Per inizializzare i tuoi moduli o generare automaticamente applicazioni di backend, la base sono uno schema ed un modello di oggetti ben definiti. Puoi modificare il codice PHP degli scaffolding, ma i moduli di amministrazione generati sono da modificare per lo più tramite configurazione. 
     1380 
     1381Il file {{{generator.yml}}} è il cuore della programmazione di backend generati. Permette una personalizzazione completa di contenuti, funzionalità e del look and feel delle viste {{{list}}} ed {{{edit}}}. Puoi gestire label, campi, suggerimenti, filtri, ordinamenti, dimensioni di pagine, tipi di input, relazioni, interazioni personalizzate e credenziali direttamente in YAML, senza una linea di codice PHP. 
     1382 
     1383Se il generatore non supporta nativamente la funzionalità di cui hai bisogno, i partial e la possibilità di fare l'override delle azioni forniscono un'estendibilità completa. Inoltre, puoi riusare i tuoi adattamenti ai meccanismi del generatore grazie ai temi.