Development

Documentation/it_IT/book/1.1/10-Forms (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/it_IT/book/1.1/10-Forms

Show
Ignore:
Author:
garak (IP: 83.103.98.10)
Timestamp:
10/16/08 15:58:09 (9 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/it_IT/book/1.1/10-Forms

    v0 v1  
     1{{{ 
     2#!WikiMarkdown  
     3 
     4Capitolo 10 - Forms 
     5=================== 
     6 
     7>**CAUTION** 
     8>Questo capitolo descrive il modo in cui le form erano implementate in symfony 1.0. Per motivi di compatibilità e poiché l'admin generator usa questo sistema, questa informazione ha valore anche per symfony 1.1. Tuttavia, se inizi un nuovo progetto con symfony 1.1, dovresti leggere anche "le Form di symfony in Azione" per maggiori informazioni sul nuovo framework. 
     9 
     10 
     11Quando si scrivono i template, molto del tempo di sviluppo è dedicato alle form; nonostante questo fatto, esse risultano spesso povere di design. Dato che è necessaria molta attenzione per gestire valori di default, formattazione, ripopolamento, alcuni sviluppatori tendono a sorvolare su aspetti importanti. Per tale motivo symfony dedica speciale attenzione a questo argomento. Il presente capitolo descrive gli strumenti che automatizzano molti di tali requisiti, velocizzando lo sviluppo: 
     12 
     13  * gli helper delle form forniscono un modo più veloce per scrivere campi di input nelle template, specialmente per elementi complessi come date, tendine, ed editor visuali. 
     14  * Quando una form serve a modificare le proprietà di un oggetto, il templating può essere velocizzato ulteriormente tramite gli helper. 
     15  * La validazione YAML facilita il ripopolamento e la validazione. 
     16  * I validatori pacchettizzano il codice necessario alla validazione dell'input. Symfony include validatori per i bisogni più comuni, ed è molto semplice aggiungerne dei nuovi. 
     17 
     18Helper delle form 
     19----------------- 
     20 
     21Nelle template, i tag HTML degli elementi delle form sono spesso mischiati con codice PHP. Gli helper delle form in symfony hanno lo scopo di semplificare questo procedimento, evitando di aprire tag `<?php echo` nel mezzo di tag `<input>`. 
     22 
     23### Tag form principale 
     24 
     25Come spiegato nel capitolo precedente, devi usare l'helper `form_tag()` per aprire una nuova form, in quanto trasforma l'azione fornita come parametro in una URL routed. Il secondo argomento può supportare opzioni aggiuntive, come ad esempio per cambiare il `method` di default, `enctype` o specificare altri attributi. Il Listato 10-1 ne mostra due esempi. 
     26 
     27Listato 10-1 - L'helper `form_tag()` 
     28 
     29    [php] 
     30    <?php echo form_tag('test/save') ?> 
     31     => <form method="post" action="/path/to/save"> 
     32 
     33    <?php echo form_tag('test/save', 'method=get multipart=true class=simpleForm') ?> 
     34     => <form method="get" enctype="multipart/form-data" class="simpleForm"action="/path/to/save"> 
     35 
     36Dato che non c'è alcun bisogno di un helper per chiudere una form, devi usare il classico tag `</form>`, anche se il codice non risulta bellissimo. 
     37 
     38### Elementi standard delle form 
     39 
     40Con gli helper delle form, ad ogni elemento viene assegnato un id dedotto automaticamente dal proprio nome. Questa non è l'unica convenzione utile. Il Listato 10-2 mostra un elenco completo degli helper delle form e le loro opzioni. 
     41 
     42Listato 10-2 - Sintassi degli helper delle form 
     43 
     44    [php] 
     45    // Campo di testo (input) 
     46    <?php echo input_tag('name', 'default value') ?> 
     47     => <input type="text" name="name" id="name" value="default value" /> 
     48 
     49    // Tutti gli helper delle form accettano un parametro addizionale 
     50    // che permette di generare attributi aggiuntivi 
     51    <?php echo input_tag('name', 'default value', 'maxlength=20') ?> 
     52     => <input type="text" name="name" id="name" value="default value"maxlength="20" /> 
     53 
     54    // Campo di testo lungo (text area) 
     55    <?php echo textarea_tag('name', 'default content', 'size=10x20') ?> 
     56     => <textarea name="name" id="name" cols="10" rows="20"> 
     57          default content 
     58        </textarea> 
     59 
     60    // Check box 
     61    <?php echo checkbox_tag('single', 1, true) ?> 
     62    <?php echo checkbox_tag('driverslicense', 'B', false) ?> 
     63     => <input type="checkbox" name="single" id="single" value="1"checked="checked" /> 
     64        <input type="checkbox" name="driverslicense" id="driverslicense"value="B" /> 
     65 
     66    // Radio button 
     67    <?php echo radiobutton_tag('status[]', 'value1', true) ?> 
     68    <?php echo radiobutton_tag('status[]', 'value2', false) ?> 
     69     => <input type="radio" name="status[]" id="status_value1" value="value1"checked="checked" /> 
     70        <input type="radio" name="status[]" id="status_value2" value="value2" /> 
     71 
     72    // Tendina (select) 
     73    <?php echo select_tag('payment', 
     74      '<option selected="selected">Visa</option> 
     75       <option>Eurocard</option> 
     76       <option>Mastercard</option>') 
     77    ?> 
     78     => <select name="payment" id="payment"> 
     79          <option selected="selected">Visa</option> 
     80          <option>Eurocard</option> 
     81          <option>Mastercard</option> 
     82        </select> 
     83 
     84    // Lista di opzioni per il tag select 
     85    <?php echo options_for_select(array('Visa', 'Eurocard', 'Mastercard'), 0) ?> 
     86     => <option value="0" selected="selected">Visa</option> 
     87        <option value="1">Eurocard</option> 
     88        <option value="2">Mastercard</option> 
     89 
     90    // Helper tendina combinato con una lista di opzioni 
     91    <?php echo select_tag('payment', options_for_select(array( 
     92      'Visa', 
     93      'Eurocard', 
     94      'Mastercard' 
     95    ), 0)) ?> 
     96     => <select name="payment" id="payment"> 
     97          <option value="0" selected="selected">Visa</option> 
     98          <option value="1">Eurocard</option> 
     99          <option value="2">Mastercard</option> 
     100        </select> 
     101 
     102    // Per specificare i nomi delle opzioni, usa una array associativo 
     103    <?php echo select_tag('name', options_for_select(array( 
     104      'Steve'  => 'Steve', 
     105      'Bob'    => 'Bob', 
     106      'Albert' => 'Albert', 
     107      'Ian'    => 'Ian', 
     108      'Buck'   => 'Buck' 
     109    ), 'Ian')) ?> 
     110     => <select name="name" id="name"> 
     111          <option value="Steve">Steve</option> 
     112          <option value="Bob">Bob</option> 
     113          <option value="Albert">Albert</option> 
     114          <option value="Ian" selected="selected">Ian</option> 
     115          <option value="Buck">Buck</option> 
     116        </select> 
     117 
     118    // Tendina con selezione multipla (i valori selezionati possono essere un array) 
     119    <?php echo select_tag('payment', options_for_select( 
     120      array('Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard'), 
     121      array('Visa', 'Mastecard'), 
     122    ), array('multiple' => true))) ?> 
     123 
     124     => <select name="payment[]" id="payment" multiple="multiple"> 
     125          <option value="Visa" selected="selected">Visa</option> 
     126          <option value="Eurocard">Eurocard</option> 
     127          <option value="Mastercard">Mastercard</option> 
     128        </select> 
     129 
     130    // Upload file 
     131    <?php echo input_file_tag('name') ?> 
     132     => <input type="file" name="name" id="name" value="" /> 
     133 
     134    // Campo password 
     135    <?php echo input_password_tag('name', 'value') ?> 
     136     => <input type="password" name="name" id="name" value="value" /> 
     137 
     138    // Campo nascosto 
     139    <?php echo input_hidden_tag('name', 'value') ?> 
     140     => <input type="hidden" name="name" id="name" value="value" /> 
     141 
     142    // Submit button (come testo) 
     143    <?php echo submit_tag('Save') ?> 
     144     => <input type="submit" name="submit" value="Save" /> 
     145 
     146    // Submit button (come immagine) 
     147    <?php echo submit_image_tag('submit_img') ?> 
     148     => <input type="image" name="submit" src="/images/submit_img.png" /> 
     149 
     150L'helper `submit_image_tag()` usa la stessa sintassi ed ha gli stessi vantaggi di `image_tag()`. 
     151 
     152>**NOTE** 
     153>Per i radio button, l'attributo `id` non è impostato per default al valore del `name`, ma ad una combinazione del nome e del valore. Questo perchè ti servono diversi tag radio con lo stesso nome per ottenere l'effetto automatico "quando ne seleziono uno si deseleziona l'altro", e la convenzione `id=name` implicherebbe avere diversi tag HTML nella stessa pagina con lo stesso id, che è severamente vietato. 
     154 
     155- 
     156 
     157>**SIDEBAR** 
     158>Gestire il submit delle form 
     159> 
     160>Come recuperi i dati inviati dagli utenti tramite form? Sono disponibili nei parametri di richiesta, per cui devi semplicemente chiamare `$this->getRequestParameter($elementName)` per ricevere i valori. 
     161> 
     162>Una buona pratica è quella di usare la stessa azione per visualizzare e gestire la form. Secondo i metodi di richiesta (GET o POST), viene chiamata la template oppure i dati vengono gestiti e poi la richiesta viene trasferita ad un'altra azione. 
     163> 
     164>     [php] 
     165>     // In mymodule/actions/actions.class.php 
     166>     public function executeEditAuthor($request) 
     167>     { 
     168>       if (!$this->getRequest()->isMethod('post')) 
     169>       { 
     170>         // Display the form 
     171>         return sfView::SUCCESS; 
     172>       } 
     173>       else 
     174>       { 
     175>         // Handle the form submission 
     176>         $name = $request->getParameter('name'); 
     177>         // ... 
     178>         $this->redirect('mymodule/anotheraction'); 
     179>       } 
     180>     } 
     181> 
     182>Per fare ciò, il target della form deve essere la stessa azione che la visualizza: 
     183> 
     184>     [php] 
     185>     // In mymodule/templates/editAuthorSuccess.php 
     186>     <?php echo form_tag('mymodule/editAuthor') ?> 
     187> 
     188>     ... 
     189 
     190Symfony offre anche helper speciali per le form per poter fare richieste asincrone in background. Il prossimo capitolo, che affronterà Ajax, ne fornirà maggiori dettagli. 
     191 
     192### Widget per gestire le date 
     193 
     194Le form sono spesso usate per recuperare date. Le date nel formato sbagliato sono la causa più comune per il fallimento della submit di una form. L'helper `input_date_tag()` assiste l'utente fornendo un utile calendario in JavaScript, se imposti l'opzione `rich` a `true`, come mostrato in Figura 10-1. 
     195 
     196Figura 10-1 - Helper per le date (rich) 
     197 
     198![Rich date input tag](/images/book/F1001.png "Rich date input tag") 
     199 
     200Se l'opzione `rich` viene omessa, l'helper stampa tre tag `<select>` per la selezione di giorni, mesi e anni. Puoi visualizzare questi elementi separatamente chiamando i loro helper (`select_day_tag()`, `select_month_tag()`, e `select_year_tag()`). I valori di default di questi elementi sono il giorno, mese e anno correnti. Il Listato 10-3 mostra gli helper delle date. 
     201 
     202Listato 10-3 - Helper per le date (select) 
     203 
     204    [php] 
     205    <?php echo input_date_tag('dateofbirth', '2005-05-03', 'rich=true') ?> 
     206     => a text input tag together with a calendar widget 
     207 
     208    // The following helpers require the DateForm helper group 
     209    <?php use_helper('DateForm') ?> 
     210 
     211    <?php echo select_day_tag('day', 1, 'include_custom=Choose a day') ?> 
     212    => <select name="day" id="day"> 
     213          <option value="">Choose a day</option> 
     214          <option value="1" selected="selected">01</option> 
     215          <option value="2">02</option> 
     216          ... 
     217          <option value="31">31</option> 
     218        </select> 
     219 
     220    <?php echo select_month_tag('month', 1, 'include_custom=Choose a month use_short_month=true') ?> 
     221    => <select name="month" id="month"> 
     222          <option value="">Choose a month</option> 
     223          <option value="1" selected="selected">Jan</option> 
     224          <option value="2">Feb</option> 
     225          ... 
     226          <option value="12">Dec</option> 
     227        </select> 
     228 
     229    <?php echo select_year_tag('year', 2007, 'include_custom=Choose a year year_end=2010') ?> 
     230     => <select name="year" id="year"> 
     231          <option value="">Choose a year</option> 
     232          <option value="2006">2006</option> 
     233          <option value="2007" selected="selected">2007</option> 
     234          ... 
     235        </select> 
     236 
     237I valori accettati per le date negli helper `input_date_tag()` sono quelli riconosciuti dalla funzione PHP `strtotime()`. Il Listato 10-4 mostra quale formato può essere usato, ed il Listato 10-5 mostra invece quelli da evitare. 
     238 
     239Listato 10-4 - Formati accettati negli helper delle date 
     240 
     241    [php] 
     242    // Funziona bene 
     243    <?php echo input_date_tag('test', '2006-04-01', 'rich=true') ?> 
     244    <?php echo input_date_tag('test', 1143884373, 'rich=true') ?> 
     245    <?php echo input_date_tag('test', 'now', 'rich=true') ?> 
     246    <?php echo input_date_tag('test', '23 October 2005', 'rich=true') ?> 
     247    <?php echo input_date_tag('test', 'next tuesday', 'rich=true') ?> 
     248    <?php echo input_date_tag('test', '1 week 2 days 4 hours 2 seconds', 'rich=true') ?> 
     249 
     250    // Restituisce null 
     251    <?php echo input_date_tag('test', null, 'rich=true') ?> 
     252    <?php echo input_date_tag('test', '', 'rich=true') ?> 
     253 
     254Listato 10-5 - Formati sbagliati negli helper delle date 
     255 
     256    [php] 
     257    // Data zero = 01/01/1970 
     258    <?php echo input_date_tag('test', 0, 'rich=true') ?> 
     259 
     260    // Date in formato non inglese non funzionano 
     261    <?php echo input_date_tag('test', '01/04/2006', 'rich=true') ?> 
     262 
     263### Editor Visuale 
     264 
     265È anche possibile usare un editor visuale nei tag `<textarea>`, grazie all'integrazione di widget quali TinyMCE e FCKEditor. Essi forniscono un'interfaccia in stile word processor con pulsanti per formattare il testo in grassetto, corsivo ed altri stili, come mostrato in Figura 10-2. 
     266 
     267Figura 10-2 - Rich text editing 
     268 
     269![Rich text editing](/images/book/F1002.png "Rich text editing") 
     270 
     271Entrambi i widget richiedono installazione manuale. Dato che la procedura è la stessa per i due widget, descriveremo qui solo quella per TinyMCE. Devi scaricare l'editor dal sito del progetto ([http://tinymce.moxiecode.com/]) e decomprimerlo in una cartella temporanea. Copia la cartella `tinymce/jscripts/tiny_mce/` nella cartella `web/js/` del tuo progetto, e definisci il percorso alla libreria nel file `settings.yml`, come mostrato nel Listato 10-6. 
     272 
     273Listato 10-6 - Impostare la libreria dell'editor TinyMCE 
     274 
     275    all: 
     276      .settings: 
     277        rich_text_js_dir:  js/tiny_mce 
     278 
     279Una volta fatto questo, imposta l'utilizzo dell'editor visuale nelle aree di testo aggiungendo l'opzione `rich=true`. Puoi anche specificare opzioni personalizzate per l'editor JavaScript, utilizzando l'opzione `tinymce_options`. Il Listato 10-7 ne mostra un esempio. 
     280 
     281Listato 10-7 - Rich text area 
     282 
     283    [php] 
     284    <?php echo textarea_tag('name', 'default content', 'rich=true size=10x20')) ?> 
     285     => a rich text edit zone powered by TinyMCE 
     286    <?php echo textarea_tag('name', 'default content', 'rich=true size=10x20tinymce_options=language:"fr",theme_advanced_buttons2:"separator"')) ?> 
     287    => a rich text edit zone powered by TinyMCE with custom parameters 
     288 
     289### Selezione del paese, della lingua e della valuta 
     290 
     291Potresti aver bisogno di visualizzare una tendina di selezione paese. Ma dato che i nomi dei paesi non sono tutti uguali nelle varie lingue, quelli presenti nell'elenco a tendina dovrebbero essere mostrati secondo la cultura dell'utente (vedi il Capitolo 13 per maggiori dettagli sulle culture). Come mostrato nel Listato 10-8, l'helper `select_country_tag()` fa tutto per te: internazionalizza i nomi dei paesi ed usa i codici ISO standard per i valori. 
     292 
     293Listato 10-8 - Helper per la selezione dei paesi 
     294 
     295    [php] 
     296    <?php echo select_country_tag('country', 'AL') ?> 
     297     => <select name="country" id="country"> 
     298          <option value="AF">Afghanistan</option> 
     299          <option value="AL" selected="selected">Albania</option> 
     300          <option value="DZ">Algeria</option> 
     301          <option value="AS">American Samoa</option> 
     302      ... 
     303 
     304Simile all'helper `select_country_tag()`, `select_language_tag()` visualizza una lista di lingue, come mostrato nel Listato 10-9. 
     305 
     306Listato 10-9 - Helper per le lingue 
     307 
     308    [php] 
     309    <?php echo select_language_tag('language', 'en') ?> 
     310     => <select name="language" id="language"> 
     311          ... 
     312          <option value="elx">Elamite</option> 
     313          <option value="en" selected="selected">English</option> 
     314          <option value="enm">English, Middle (1100-1500)</option> 
     315          <option value="ang">English, Old (ca.450-1100)</option> 
     316          <option value="myv">Erzya</option> 
     317          <option value="eo">Esperanto</option> 
     318          ... 
     319 
     320Il terzo helper è `select_currency_tag()`, che mostra una lista di valute, come mostrato nel Listato 10-10. 
     321 
     322Listato 10-10 - Helper per scegliere le valute 
     323 
     324    [php] 
     325    <?php echo select_currency_tag('currency', 'EUR') ?> 
     326     => <select name="currency" id="currency"> 
     327          ... 
     328          <option value="ETB">Ethiopian Birr</option> 
     329          <option value="ETD">Ethiopian Dollar</option> 
     330          <option value="EUR" selected="selected">Euro</option> 
     331          <option value="XBA">European Composite Unit</option> 
     332          <option value="XEU">European Currency Unit</option> 
     333          ... 
     334 
     335>**NOTE** 
     336>Tutti e tre gli helper accettano come terzo parametro una array di opzioni. Questa può limitare le opzioni visualizzato ad un certo sottoinsieme: `array('countries' => array ('FR', 'DE'))`. Per `select_language_tag()` l'opzione si chiama `languages` e per `select_currency_tag()` si chiama `currencies`. Nella maggior parte dei casi ha senso limitare ad un insieme di valori conosciuti e supportati, specialmente visto che le liste potrebbero contenere dei valori desueti. 
     337>`select_currency_tag()` offre un'ulteriore opzione chiamata `display` che influenza cosa viene mostrato nelle option. Può essere uno tra `symbol`, `code` o `name`. 
     338 
     339Helper per gli oggetti 
     340---------------------- 
     341 
     342Quando gli elementi di una form sono usati per modificare le proprietà di un oggetto, gli helper dei link possono diventare noiosi da scrivere. Ad esempio, per modificare l'attributo `telephone` dell'oggetto `Customer`, scriveresti: 
     343 
     344    [php] 
     345    <?php echo input_tag('telephone', $customer->getTelephone()) ?> 
     346    => <input type="text" name="telephone" id="telephone" value="0123456789" /> 
     347 
     348Per evitare di ripetere il nome dell'attributo, symfony mette a disposizione helper alternativi, per ogni oggetto della form. Un helper delle form per un oggetto deduce il nome ed il valore di default dell'elemento della form dall'oggetto e dal nome del metodo. Il precedente `input_tag()` è equivalente a: 
     349 
     350    [php] 
     351    <?php echo object_input_tag($customer, 'getTelephone') ?> 
     352    => <input type="text" name="telephone" id="telephone" value="0123456789" /> 
     353 
     354Potrebbe non sembrare un grande risparmio per `object_input_tag()`. Comunque ogni helper standard delle form possiede il corrispettivo per l'oggetto,  ed essi possiedono tutti la stessa sintassi. Ciò velocizza molto la generazione delle form. Per questo motivo gli helper degli oggetti sono usati estensivamente nello scaffolding e nella generazione dei pannelli di amministrazione (v. il Capitolo 14). Il Listato 10-11 mostra una lista di tali helper. 
     355 
     356Listato 10-11 - Sintassi degli helper per gli oggetti 
     357 
     358    [php] 
     359    <?php echo object_input_tag($object, $method, $options) ?> 
     360    <?php echo object_input_date_tag($object, $method, $options) ?> 
     361    <?php echo object_input_hidden_tag($object, $method, $options) ?> 
     362    <?php echo object_textarea_tag($object, $method, $options) ?> 
     363    <?php echo object_checkbox_tag($object, $method, $options) ?> 
     364    <?php echo object_select_tag($object, $method, $options) ?> 
     365    <?php echo object_select_country_tag($object, $method, $options) ?> 
     366    <?php echo object_select_language_tag($object, $method, $options) ?> 
     367 
     368Non esiste un helper `object_password_tag()`, in quanto è una pratica sbagliata fornire un valore di default nei tag password. 
     369 
     370>**CAUTION** 
     371>A differenza degli helper normali delle form, quelli degli oggetti sono disponibili solo se dichiari esplicitamente l'uso dell'helper `Object` nella tua template, tramite `use_helper('Object')`. 
     372 
     373Fra tutti gli helper degli oggetti, i più interessanti sono `objects_for_select()` e `object_select_tag()`, che riguardano i menu a tendina. 
     374 
     375### Popolare menu a tendina con oggetti 
     376 
     377L'helper `options_for_select()`, descritto precedentemente con gli altri helper standard, trasforma un array associativo di PHP in una lista di option, come mostrato nel Listato 10-12. 
     378 
     379Listato 10-12 - Creare una lista di option basata su array con `options_for_select()` 
     380 
     381    [php] 
     382    <?php echo options_for_select(array( 
     383      '1' => 'Steve', 
     384      '2' => 'Bob', 
     385      '3' => 'Albert', 
     386      '4' => 'Ian', 
     387      '5' => 'Buck' 
     388    ), 4) ?> 
     389     => <option value="1">Steve</option> 
     390        <option value="2">Bob</option> 
     391        <option value="3">Albert</option> 
     392        <option value="4" selected="selected">Ian</option> 
     393        <option value="5">Buck</option> 
     394 
     395Supponi che tu avessi già un array di oggetti della classe `Author`, come risultato di una query Propel. Se volessi costruire una lista di option basata su tale array, dovresti eseguire un loop al suo interno e trovare tutti gli `id` e `name`, come mostrato nel Listato 10-13. 
     396 
     397Listato 10-13 - Creare una lista di option basata su array di oggetti con `options_for_select()` 
     398 
     399    [php] 
     400    // Nell'azione 
     401    $options = array(); 
     402    foreach ($authors as $author) 
     403    { 
     404      $options[$author->getId()] = $author->getName(); 
     405    } 
     406    $this->options = $options; 
     407 
     408    // Nella template 
     409    <?php echo options_for_select($options, 4) ?> 
     410 
     411Questo modo di procedere accade talmente spesso che symfony possiede un helper per automatizzarlo: `objects_for_select()`. L'helper si aspetta due parametri aggiuntivi: i nomi dei metodi da usare per recuperare i `value` ed il contenuto del testo per il tag `<option>`. Cosi', il Listato 10-13 è equivalente alla seguente forma più semplice: 
     412 
     413    [php] 
     414    <?php echo objects_for_select($authors, 'getId', 'getName', 4) ?> 
     415 
     416Questo è facile e veloce, ma symfony fa ancora di più, quando si ha a che fare con chiavi importate. 
     417 
     418### Creare un menu a tendina basato su chiavi importate 
     419 
     420I valori di una colonna definita come chiave importata sono le chiavi primarie di record di un'altra tabella. Se, per esempio, la tabella `article` ha una colonna `author_id` definita come chiave importata della tabella `author`, i valori possibili per tale colonna sono gli `id` dei record della tabella `author`. Fondamentalmente, un menu a tendina per modificare l'autore di un articolo sarebbe generato come dal Listato 10-14. 
     421 
     422Listato 10-14 - Creare una lista di option basata su chiavi importate con `objects_for_select()` 
     423 
     424    [php] 
     425    <?php echo select_tag('author_id', objects_for_select( 
     426      AuthorPeer::doSelect(new Criteria()), 
     427      'getId', 
     428      '__toString', 
     429      $article->getAuthorId() 
     430    )) ?> 
     431    => <select name="author_id" id="author_id"> 
     432          <option value="1">Steve</option> 
     433          <option value="2">Bob</option> 
     434          <option value="3">Albert</option> 
     435          <option value="4" selected="selected">Ian</option> 
     436          <option value="5">Buck</option> 
     437        </select> 
     438 
     439L'helper `object_select_tag()` fa tutto da solo. Mostra un menu a tendina popolato con i nomi dei possibili record della tabella esterna. L'helper può capire la tabella e la colonna esterne dallo schema, per cui la sua sintassi è concisa. Il Listato 10-14 è equivalente a questo: 
     440 
     441    [php] 
     442    <?php echo object_select_tag($article, 'getAuthorId') ?> 
     443 
     444L'helper `object_select_tag()` capisce il nome della relativa classe peer (nell'esempio `AuthorPeer`) dal nome del metodo passato come parametro. Ad ogni modo puoi specificare la classe che preferisci specificando l'opzione `related_class` come terzo argomento. Il testo che appare nel tag `<option>` è il nome del record, risultato del metodo `__toString()` dell'oggetto (se `$author->__toString()` non fosse definito, sarebbe riportata la chiave primaria). Inoltre, la lista delle opzioni viene costruita tramite il metodo doSelect() con un Criteria vuoto; restituisce tutti i record ordinati per data di creazione. Se preferisci visualizzare solo un sottoinsieme dei record con in ordine specifico, crea un metodo nella classe peer che restituisca tale selezione come array di oggetti, ed impostalo come opzione `peer_method`. Infine, puoi aggiungere una option vuota od una personalizzata all'inizio del menu a tendina impostando le opzioni `include_blank` e `include_custom`. Il Listato 10-15 mostra tali opzioni per l'helper `object_select_tag()`. 
     445 
     446Listato 10-15 - Opzioni per l'helper `object_select_tag()` 
     447 
     448    [php] 
     449    // Sintassi di base 
     450    <?php echo object_select_tag($article, 'getAuthorId') ?> 
     451    // Builds the list from AuthorPeer::doSelect(new Criteria()) 
     452 
     453    // Cambiare la classe peer usata per trovare i valori possibili 
     454    <?php echo object_select_tag($article, 'getAuthorId', 'related_class=Foobar') ?> 
     455    // Builds the list from FoobarPeer::doSelect(new Criteria()) 
     456 
     457    // Cambiare il metodo peer usato per trovare i valori possibili 
     458    <?php echo object_select_tag($article, 'getAuthorId','peer_method=getMostFamousAuthors') ?> 
     459    // Builds the list from AuthorPeer::getMostFamousAuthors(new Criteria()) 
     460 
     461    // Aggiungere un <option value="">&nbsp;</option> all'inizio della lista 
     462    <?php echo object_select_tag($article, 'getAuthorId', 'include_blank=true') ?> 
     463 
     464    // Aggiungere un <option value="">Choose an author</option> all'inizio della lista 
     465    <?php echo object_select_tag($article, 'getAuthorId', 
     466      'include_custom=Choose an author') ?> 
     467 
     468### Aggiornare oggetti 
     469 
     470Una form completamente dedicata alla modifica delle proprieta' degli oggetti e che utilizza i loro helper è molto facile da gestire in un'azione. Ad esempio, se hai un oggetto della classe `Author` con gli attributi `name`, `age`, e `address`, la form può essere codificata come mostrato nel Listato 10-16. 
     471 
     472Listato 10-16 - Una form con solamente helper degli oggetti 
     473 
     474    [php] 
     475    <?php echo form_tag('author/update') ?> 
     476      <?php echo object_input_hidden_tag($author, 'getId') ?> 
     477      Name: <?php echo object_input_tag($author, 'getName') ?><br /> 
     478      Age:  <?php echo object_input_tag($author, 'getAge') ?><br /> 
     479      Address: <br /> 
     480             <?php echo object_textarea_tag($author, 'getAddress') ?> 
     481    </form> 
     482 
     483L'azione `update` del modulo `author`, chiamata quando la form viene spedita, può facilmente aggiornare l'oggetto tramite il modificatore `fromArray()` generato da Propel, come mostrato nel Listato 10-17. 
     484 
     485Listato 10-17 - Gestire i dati da un form tramite gli helper degli oggetti 
     486 
     487    [php] 
     488    public function executeUpdate($request) 
     489    { 
     490      $author = AuthorPeer::retrieveByPk($request->getParameter('id')); 
     491      $this->forward404Unless($author); 
     492 
     493      $author->fromArray($this->getRequest()->getParameterHolder()->getAll(),AuthorPeer::TYPE_FIELDNAME); 
     494      $author->save(); 
     495 
     496      return $this->redirect('/author/show?id='.$author->getId()); 
     497    } 
     498 
     499Validazione delle form 
     500---------------------- 
     501 
     502>**NOTE** 
     503>Le caratteristiche descritte in questa sezione sono deprecate in symfony 1.1 e funzionano solamente abilitando il plugin `sfCompat10`. 
     504 
     505Il Capitolo 6 ha spiegato come utilizzare i metodi `validateXXX()` nelle azioni delle classi per validare i parametri di richiesta. Ma se utilizzi tale tecnica per validare tutti i dati spediti da una form, finirai per scrivere ripetutamente lo stesso codice. Symfony fornisce un metodo alternativo per la validazione delle form, che si basa su un file YAML, invece di codice PHP nelle classi. 
     506 
     507Per dimostrare tale tecnica, prendi in considerazione la semplice form del Listato 10-18. È una classica form di contatto, con i campi `name, email, age,` e `message`. 
     508 
     509Listato 10-18 - Semplice form di contatto, in `modules/contact/templates/indexSuccess.php` 
     510 
     511    [php] 
     512    <?php echo form_tag('contact/send') ?> 
     513      Name:    <?php echo input_tag('name') ?><br /> 
     514      Email:   <?php echo input_tag('email') ?><br /> 
     515      Age:     <?php echo input_tag('age') ?><br /> 
     516      Message: <?php echo textarea_tag('message') ?><br /> 
     517      <?php echo submit_tag() ?> 
     518    </form> 
     519 
     520Il principio della validazione delle form è che se l'utente invia dati non validi, la pagina successiva mostra un errore. Definiamo quali sono i dati validi per la form dell'esempio: 
     521 
     522  * Il campo `name` è obbligatorio. Deve essere testo di lunghezza fra 2 e 100 caratteri. 
     523  * Il campo `email` è obbligatorio. Deve essere testo di lunghezza fra 2 e 100 caratteri, e deve essere un indirizzo email valido. 
     524  * Il campo `age` è obbligatorio. Deve essere un intero fra 0 e 120 caratteri. 
     525  * Il campo `message` è obbligatorio. 
     526 
     527Potresti definire regole molto più complesse, ma questa vanno bene per mostrare le possibilità della validazione. 
     528 
     529>**NOTE** 
     530>La validazione delle form può avvenire lato server e/o lato client. Quella lato server è assolutamente obbligatoria per evitare la corruzione del database con dati erronei. La validazione lato client è opzionale, ma migliora molto la fruibilità. Essa è realizzata tramite JavaScript personalizzato. 
     531 
     532### Validatori 
     533 
     534Come puoi vedere i campi `name` e `email` nell'esempio condividono una parte delle regole. Alcune regole di validazione compaiono talmente spesso nelle form che symfony pacchettizza il codice che le implementa in validatori. Un validatore è una semplice classe che dispone di un metodo `execute()`. Tale metodo si aspetta il valore di un campo come parametro, e restituisce `true` se il valore è valido, `false` altrimenti. 
     535 
     536Symfony dispone di diversi validatori (descritti nella sezione "I validatori standard di symfony" più avanti in questo capitolo), ma per ora ci soffermeremo su `sfStringValidator`. Questo validatore accerta che l'input sia una stringa, e che la sua lunghezza sia compresa tra i due valori specifici (definiti alla chiamata del metodo `initialize()`). Questo è esattamente ciò che ci serve per la validazione di `name`. Il Listato 10-19 mostra come usare tale validatore. 
     537 
     538Listato 10-19 - Validare parametri di richiesta tramite validatori riutilizzabili, in `modules/contact/action/actions.class.php` 
     539 
     540    [php] 
     541    public function validateSend($request) 
     542    { 
     543      $name = $request->getParameter('name'); 
     544 
     545      // The name field is required 
     546      if (!$name) 
     547      { 
     548        $this->getRequest()->setError('name', 'The name field cannot be left blank'); 
     549 
     550        return false; 
     551      } 
     552 
     553      // The name field must be a text entry between 2 and 100 characters 
     554      $myValidator = new sfStringValidator(); 
     555      $myValidator->initialize($this->getContext(), array( 
     556        'min'       => 2, 
     557        'min_error' => 'This name is too short (2 characters minimum)', 
     558        'max'       => 100, 
     559        'max_error' => 'This name is too long. (100 characters maximum)', 
     560      )); 
     561      if (!$myValidator->execute($name)) 
     562      { 
     563        return false; 
     564      } 
     565 
     566      return true; 
     567    } 
     568 
     569Se un utente spedisce la form del Listato 10-18 con il valore "a" nel campo `name`, il metodo `execute()` di `sfStringValidator` restituirà `false` (in quanto la lunghezza è minore di due). Quindi il metodo `validateSend()` fallirà, e sarà chiamato il metodo `handleErrorSend()` invece di `executeSend()`. 
     570 
     571>**TIP** 
     572>Il metodo `setError()` della classe `sfRequest` fornisce informazioni alla template affinchè essa possa mostrare il messaggio di errore (come spiegato nella sezione "Mostrare messaggi di errore nelle form" più avanti in questo capitolo). I validatori impostano gli errori internamente, quindi puoi definire errori diversi per casi diversi di dati non validi. Questo è lo scopo dei parametri di inizializzazione `min_error` e `max_error` di `sfStringValidator`. 
     573 
     574Tutte le regole definite nel'esempio possono essere tradotte nei validatori: 
     575 
     576  * name: sfStringValidator (min=2, max=100) 
     577  * email: sfStringValidator (min=2, max=100) e sfEmailValidator 
     578  * age: sfNumberValidator (min=0, max=120) 
     579 
     580Il fatto che un campo sia obbligatorio non è gestito da un validatore. 
     581 
     582### File per la validazione 
     583 
     584Potresti facilmente implementare la validazione della form di contatto nel metodo PHP `validateSend()`, ma questo implicherebbe ripetere molto codice. Symfony offre un metodo alternativo per definire regole di validazione per una form, che coinvolge YAML. Ad esempio, il Listato 10-20 mostra la traduzione delle regole di validazione del campo `name`, ed il risultato è lo stesso di quello del Listato 10-18. 
     585 
     586Listato 10-20 - File di validazione, in `modules/contact/validate/send.yml` 
     587 
     588    fields: 
     589      name: 
     590        required: 
     591          msg:       The name field cannot be left blank 
     592        sfStringValidator: 
     593          min:       2 
     594          min_error: This name is too short (2 characters minimum) 
     595          max:       100 
     596          max_error: This name is too long. (100 characters maximum) 
     597 
     598In un file per la validazione, l'header `fields` elenca i campi che devono essere validati, se sono obbligatori ed i validatori da usare su di essi quando presentano dei valori. I parametri di ogni validatore sono gli stessi che useresti per inizializzare un validatore manualmente. Un campo può essere validato da tanti validatori quanti ne siano necessari. 
     599 
     600>**NOTE** 
     601>Il processo di validazione non si ferma quando un validatore fallisce. Symfony controlla tutti i validatori e dichiara il fallimento se almeno uno di essi fallisce. Ed anche se alcune delle regole falliscono, symfony continuerà a cercare un metodo `validateXXX()` e ad eseguirlo. Per cui le due tecniche di validazione sono complementari. Il vantaggio è che in una form con fallimenti multipli, tutti gli errori vengono mostrati. 
     602 
     603I file per la validazione sono situati nella cartella `validate/` di ogni modulo, e portano il nome dell'azione che devono validare. Ad esempio, il Listato 10-20 deve essere memorizzato in un file chiamato `validate/send.yml`. 
     604 
     605### Rivisualizzare la form 
     606 
     607Per default, ogni qualvolta un processo di validazione fallisca, symfony controlla l'esistenza del metodo `handleErrorSend()` nell'azione, e se non esiste mostra la template `sendError.php`. 
     608 
     609Il metodo abituale di informare l'utente di una validazione fallita è quello di mostrare nuovamente la form con un messaggio di errore. A questo scopo, devi fare l'override del metodo `handleErrorSend()` e concluderlo con la ridirezione all'azione che mostra la form (nell'esempio, `module/index`), come mostrato nel Listato 10-21. 
     610 
     611Listato 10-21 - Mostrare nuovamente la form, in `modules/contact/actions/actions.class.php` 
     612 
     613    [php] 
     614    class ContactActions extends sfActions 
     615    { 
     616      public function executeIndex() 
     617      { 
     618        // Display the form 
     619      } 
     620 
     621      public function handleErrorSend() 
     622      { 
     623        $this->forward('contact', 'index'); 
     624      } 
     625 
     626      public function executeSend() 
     627      { 
     628        // Handle the form submission 
     629      } 
     630    } 
     631 
     632Se scegli di utilizzare la stessa azione sia per visualizzare la form che per gestirne i dati, allora il metodo `handleErrorSend()` può semplicemente restituire `sfView::SUCCESS` per rivisualizzare la form tramite `sendSuccess.php`, come mostrato nel Listato 10-22. 
     633 
     634Listato 10-22 - Un'unica azione per visualizzare e gestire la form, in `modules/contact/actions/actions.class.php` 
     635 
     636    [php] 
     637    class ContactActions extends sfActions 
     638    { 
     639      public function executeSend() 
     640      { 
     641        if (!$this->getRequest()->isMethod('post')) 
     642        { 
     643          // Prepara i dati per la template 
     644 
     645          // Visualizza la form 
     646          return sfView::SUCCESS; 
     647        } 
     648        else 
     649        { 
     650          // Gestisce i dati 
     651          ... 
     652          $this->redirect('mymodule/anotheraction'); 
     653        } 
     654      } 
     655      public function handleErrorSend() 
     656      { 
     657        // Prepara i dati per la template 
     658  
     659        // Visualizza la form 
     660        return sfView::SUCCESS; 
     661      } 
     662    } 
     663 
     664La logica necessaria alla preparazione dei dati per la template può essere spostata (refactoring) in un metodo protetto, così da evitare la duplicazione del codice nei metodi `executeSend()` e `handleErrorSend()`. 
     665 
     666Con questa nuova configurazione, quando un utente scrive un nome non valido la form viene visualizzata nuovamente, ma i dati che aveva immesso sono perduti e non c'è alcun messaggio che spiega la natura dell'errore. A questo scopo devi modificare la template che visualizza la form, per inserire un messaggio di errore vicino al campo che lo ha generato. 
     667 
     668### Mostrare messaggi di errore nelle form 
     669 
     670I messaggi di errore definiti come parametri dei validatori vengono aggiunti alla richiesta quando un campo fallisce la validazione (esattamente come se tu aggiungessi un errore manualmente con `setError()`, come mostrato nel Listato 10-19). L'oggetto `sfRequest` fornisce due metodi utili per recuperare il messaggio di errore: `hasError()` e `getError()`, ognuno dei quali si aspetta un nome di campo come parametro. Inoltre puoi visualizzare un messaggio all'inizio della form tramite il metodo `hasErrors()` per far notare il fatto che ci sono uno o più campi che hanno fallito la validazione. I Listati 10-23 e 10-24 mostrano come usare tali metodi. 
     671 
     672Listato 10-22 - Mostrare un messaggio di errore all'inizio della form, in `templates/indexSuccess.php` 
     673 
     674    [php] 
     675    <?php if ($sf_request->hasErrors()): ?> 
     676      <p>The data you entered seems to be incorrect. 
     677      Please correct the following errors and resubmit:</p> 
     678      <ul> 
     679      <?php foreach($sf_request->getErrors() as $name => $error): ?> 
     680        <li><?php echo $name ?>: <?php echo $error ?></li> 
     681      <?php endforeach; ?> 
     682      </ul> 
     683    <?php endif; ?> 
     684 
     685Listato 10-23 - Mostrare un messaggio di errore all'interno della form, in `templates/indexSuccess.php` 
     686 
     687    [php] 
     688    <?php echo form_tag('contact/send') ?> 
     689      <?php if ($sf_request->hasError('name')): ?> 
     690        <?php echo $sf_request->getError('name') ?> <br /> 
     691      <?php endif; ?> 
     692      Name:    <?php echo input_tag('name') ?><br /> 
     693      ... 
     694      <?php echo submit_tag() ?> 
     695    </form> 
     696 
     697L'uso condizionale del metodo `getError()` del Listato 10-23 è un pò lungo da scrivere. Per tale motivo symfony mette a disposizione un helper `form_error()`, a patto che tu abbia definito l'utilizzo del gruppo di helper di cui fa parte, `Validation`. Il Listato 10-25 sostituisce il 10-24 con l'utilizzo di tale helper. 
     698 
     699Listato 10-25 - Mostrare un messaggio di errore all'interno della form, metodo più breve 
     700 
     701    [php] 
     702    <?php use_helper('Validation') ?> 
     703    <?php echo form_tag('contact/send') ?> 
     704 
     705               <?php echo form_error('name') ?><br /> 
     706      Name:    <?php echo input_tag('name') ?><br /> 
     707      ... 
     708      <?php echo submit_tag() ?> 
     709    </form> 
     710 
     711L'helper `form_error()` aggiunge un carattere speciale prima e dopo il messaggio di errore, per renderlo più visibile. Per default, tale carattere è una freccia rivolta verso il basso (corrispondente all'entità &darr;), ma puoi cambiarlo nel file settings.yml: 
     712 
     713    all: 
     714      .settings: 
     715        validation_error_prefix:    ' &darr;&nbsp;' 
     716        validation_error_suffix:    ' &nbsp;&darr;' 
     717 
     718In caso di validazione fallita, ora la form mostra correttamente gli errori, ma i dati inseriti dall'utente sono perduti. Per rendere la form più user-friendly occorre ripopolarla. 
     719 
     720### Ripopolazione della form 
     721 
     722Siccome la gestione dell'errore avviene tramite il metodo `forward()` (come mostrato nel Listato 10-21), la richiesta originale è ancora accessibile, ed i dati inseriti dall'utente sono nei parametri di richiesta. Quindi potresti ripopolare la form aggiungendo valori di default, come mostrato nel Listato 10-26. 
     723 
     724Listato 10-26 - Impostare valori di default per ripopolare la form quando la validazione fallisce, in `templates/indexSuccess.php` 
     725 
     726    [php] 
     727    <?php use_helper('Validation') ?> 
     728    <?php echo form_tag('contact/send') ?> 
     729               <?php echo form_error('name') ?><br /> 
     730      Name:    <?php echo input_tag('name', $sf_params->get('name')) ?><br /> 
     731               <?php echo form_error('email') ?><br /> 
     732      Email:   <?php echo input_tag('email', $sf_params->get('email')) ?><br /> 
     733               <?php echo form_error('age') ?><br /> 
     734      Age:     <?php echo input_tag('age', $sf_params->get('age')) ?><br /> 
     735               <?php echo form_error('message') ?><br /> 
     736      Message: <?php echo textarea_tag('message', $sf_params->get('message')) ?><br /> 
     737      <?php echo submit_tag() ?> 
     738    </form> 
     739 
     740Ma ancora una volta, tale metodo è noioso da scrivere. Symfony fornisce un metodo alternativo per la ripopolazione, basato su un file YAML, senza modificare i valori di default degli elementi. Abilita semplicemente la funzione `fillin:` per la form, con la sintassi descritta nel Listato 10-27. 
     741 
     742Listato 10-27 - Attivare `fillin` per ripopolare la form, in `validate/send.yml` 
     743 
     744    fillin: 
     745      enabled: true  # Enable the form repopulation 
     746      param: 
     747        name: test  # Form name, not needed if there is only one form in the page 
     748        skip_fields:   [email]  # Do not repopulate these fields 
     749        exclude_types: [hidden, password] # Do not repopulate these field types 
     750        check_types:   [text, checkbox, radio, password, hidden] # Do repopulate these 
     751 
     752Per default, la ripopolazione automatica funziona per gli elementi text input, check boxe, radio button, text area, e select (normali e multiple), ma non per le password ed i tag `hidden`. La funzione `fillin` non funziona per i tag `file`. 
     753 
     754>**NOTE** 
     755>La funzione `fillin` funziona facendo il parsing in XML del contenuto della risposta immediatamente prima di spedirla all'utente. Se la risposta non è un documento XHTML valido, `fillin` potrebbe non funzionare correttamente. 
     756 
     757Potresti voler trasformare i valori inseriti dall'utente prima di riscriverli nella form. Escaping, URL rewriting, trasformazione di caratteri speciali in entità, e tutte le altre trasformazioni che possono essere chiamate tramite una funzione possono essere applicate ai campi della tua form se definisci tale trasformazione sotto la chiave `converters:`, come mostrato nel Listato 10-28. 
     758 
     759Listato 10-28 - Convertire input prima del `fillin`, in `validate/send.yml` 
     760 
     761    fillin: 
     762      enabled: true 
     763      param: 
     764        name: test 
     765        converters:         # Converters to apply 
     766          htmlentities:     [first_name, comments] 
     767          htmlspecialchars: [comments] 
     768 
     769### Validatori standard di symfony 
     770 
     771Symfony include alcuni validatori standard che puoi utilizzare nelle tue form: 
     772 
     773  * `sfStringValidator` 
     774  * `sfNumberValidator` 
     775  * `sfEmailValidator` 
     776  * `sfUrlValidator` 
     777  * `sfRegexValidator` 
     778  * `sfCompareValidator` 
     779  * `sfPropelUniqueValidator` 
     780  * `sfFileValidator` 
     781  * `sfCallbackValidator` 
     782 
     783Ognuno di essi possiede un insieme di parametri di default e messaggi di errore, ma ne puoi fare facilmente l'override tramite il metodo `initialize()` dei validatori, od in un file YAML. La sezione seguente descrive i validatori e ne mostra esempi d'uso. 
     784 
     785#### Validatore di stringhe 
     786 
     787`sfStringValidator` permette di applicare restrizioni di tipo stringa ad un parametro. 
     788 
     789    sfStringValidator: 
     790      values:       [foo, bar] 
     791      values_error: The only accepted values are foo and bar 
     792      insensitive:  false  # If true, comparison with values is case insensitive 
     793      min:          2 
     794      min_error:    Please enter at least 2 characters 
     795      max:          100 
     796      max_error:    Please enter less than 100 characters 
     797 
     798#### Validatore di numeri 
     799 
     800`sfNumberValidator` controlla se un parametro è un numero e permette di applicare restrizioni sulla dimensione. 
     801 
     802    sfNumberValidator: 
     803      nan_error:    Please enter an integer 
     804      min:          0 
     805      min_error:    The value must be at least zero 
     806      max:          100 
     807      max_error:    The value must be less than or equal to 100 
     808 
     809#### Validatore di email 
     810 
     811`sfEmailValidator` controlla se un parametro è un indirizzo di email valido. 
     812 
     813    sfEmailValidator: 
     814      strict:       true 
     815      email_error:  This email address is invalid 
     816 
     817RFC822 definisce il formato per gli indirizzi email. Comunque esso è più permissivo dei formati generalmente accettati. Ad esempio, secondo l'RFC `me@localhost` è un indirizzo di email valido, ma probabilmente tu non lo vorresti accettare. Quando il parametro `strict` è impostato a `true` (che è il suo valore di default), solo le email che corrispondono al pattern `name@domain.extension` sono valide. Quando è impostato su `false`, come regola viene usata RFC822. 
     818 
     819#### Validatore di URL 
     820 
     821`sfUrlValidator` controlla se un campo è una URL corretta. 
     822 
     823    sfUrlValidator: 
     824      url_error:    This URL is invalid 
     825 
     826#### Validatore di espressioni regolari 
     827 
     828`sfRegexValidator` ti permette di confrontare un valore con un una espressione regolare in formato Perl. 
     829 
     830    sfRegexValidator: 
     831      match:        No 
     832      match_error:  Posts containing more than one URL are considered as spam 
     833      pattern:      /http.*http/si 
     834 
     835Il parametro `match` determina se per essere valido un parametro di richiesta deve corrispondere ad pattern (valore `Yes`) oppure no (valore `No`). 
     836 
     837#### Validatore di confronto 
     838 
     839`sfCompareValidator` confronta due parametri di richiesta. Risulta molto utile per il controllo delle password. 
     840 
     841    fields: 
     842      password1: 
     843        required: 
     844          msg:      Please enter a password 
     845      password2: 
     846        required: 
     847          msg:      Please retype the password 
     848        sfCompareValidator: 
     849          check:    password1 
     850          compare_error: The two passwords do not match 
     851 
     852Il parametro `check` contiene il nome del campo che deve essere coincidente al campo in esame. 
     853 
     854Per default il validatore controlla che i parametri siano uguali. Puoi cambiare questo comportamento specificando un parametro `operator`. Gli operatori possibili sono: `>`, `>=`, `<`, `<=`, `==` e `!=`. 
     855 
     856#### Validatore di Propel unici 
     857 
     858`sfPropelUniqueValidator` assicura che il valore di un parametro di richiesta non esista già nel tuo database. Risulta molto utile per indici unici. 
     859 
     860    fields: 
     861      nickname: 
     862        sfPropelUniqueValidator: 
     863          class:        User 
     864          column:       login 
     865          unique_error: This login already exists. Please choose another one. 
     866 
     867In questo esempio, il validatore controlla se nel database esiste già un record della classe `User` dove la colonna `column` abbia lo stesso valore del campo da verificare. 
     868 
     869#### Validatore di file 
     870 
     871`sfPropelFileValidator` applica restrizioni sul formato (array di mime-type) e sulle dimensioni dei campi di upload. 
     872 
     873    fields: 
     874      image: 
     875        required: 
     876          msg:      Please upload an image file 
     877          file:     True 
     878        sfFileValidator: 
     879          mime_types: 
     880            - 'image/jpeg' 
     881            - 'image/png' 
     882            - 'image/x-png' 
     883            - 'image/pjpeg' 
     884          mime_types_error: Only PNG and JPEG images are allowed 
     885          max_size:         512000 
     886          max_size_error:   Max size is 512Kb 
     887 
     888Fai attenzione a che l'attributo `file` sia impostato a `True`, e che la template dichiari la form come multipart. 
     889 
     890#### Validatore callback 
     891 
     892`sfPropelCallbackValidator` delega la validazione ad un metodo di terze parti. Tale metodo deve restituire `true` o `false`. 
     893 
     894    fields: 
     895      account_number: 
     896        sfCallbackValidator: 
     897          callback:      is_integer 
     898          invalid_error: Please enter a number. 
     899      credit_card_number: 
     900        sfCallbackValidator: 
     901          callback:      [myTools, validateCreditCard] 
     902          invalid_error: Please enter a valid credit card number. 
     903 
     904Il metodo o la funzione di callback riceve il valore da verificare come primo parametro. Risulta molto utile quando vuoi riutilizzare metodi o funzioni esistenti, invece di scrivere un'intera classe per la validazione. 
     905 
     906>**TIP** 
     907>Puoi anche scrivere i tuoi validatori, come descritto nella sezione "Creare un validatore personalizzato" più avanti in questo capitolo. 
     908 
     909### Chiamate a validatori 
     910 
     911Se ti rendi conto che hai bisogno di ripetere un validatore e le sue impostazioni, lo puoi pacchettizzare in una chiamata a validatore. Nell'esempio della form di contatto, il campo `email` necessita dello stesso `sfStringValidator` del campo `name`. Per cui potresti creare la tua chiamata `myStringValidator` per evitare di ripetere le stesse impostazioni. Per fare ciò, aggiungi una label `myStringValidator` sotto l'header `validators:`, ed imposta le chiavi `class` e `param` con i dettagli relativi. Puoi utilizzare la chiamata sotto la sezione `fields` come un qualsiasi validatore regolare, come mostrato nel Listato 10-29. 
     912 
     913Listato 10-29 - Riutilizzare chiamate a validatori, in `validate/send.yml` 
     914 
     915    validators: 
     916      myStringValidator: 
     917        class: sfStringValidator 
     918        param: 
     919          min:       2 
     920          min_error: This field is too short (2 characters minimum) 
     921          max:       100 
     922          max_error: This field is too long (100 characters maximum) 
     923 
     924    fields: 
     925      name: 
     926        required: 
     927          msg:       The name field cannot be left blank 
     928        myStringValidator: 
     929      email: 
     930        required: 
     931          msg:       The email field cannot be left blank 
     932        myStringValidator: 
     933        sfEmailValidator: 
     934          email_error:  This email address is invalid 
     935 
     936### Restringere la validazione ad un metodo 
     937 
     938Per default, i validatori impostati vengono utilizzati ogni qualvolta un'azione riceve parametri in POST. Puoi fare l'override di tale impostazione sia globalmente che campo per campo, specificando un altro valore nella chiave `method`, per permettere validazioni differenti su metodi differenti, come mostrato nel Listato 10-30. 
     939 
     940Listato 10-30 - Definire quando testare un campo, in `validate/send.yml` 
     941 
     942    methods:         [post]     # This is the default setting 
     943 
     944    fields: 
     945      name: 
     946        required: 
     947          msg:       The name field cannot be left blank 
     948        myStringValidator: 
     949      email: 
     950        methods:     [post, get] # Overrides the global methods settings 
     951        required: 
     952          msg:       The email field cannot be left blank 
     953        myStringValidator: 
     954        sfEmailValidator: 
     955          email_error:  This email address is invalid 
     956 
     957### Com'è fatto un file di validazione? 
     958 
     959Fino ad ora hai visto solo pezzetti di file di validazione. Quando assembli il tutto, le regole di validazione trovano una chiara traduzione in YAML. Il Listato 10-31 mostra un file completo per la validazione dell'esempio della form di contatto, contenente tutte le regole viste finora. 
     960 
     961Listato 10-31 - File di validazione completo 
     962 
     963    fillin: 
     964      enabled:      true 
     965 
     966    validators: 
     967      myStringValidator: 
     968        class: sfStringValidator 
     969        param: 
     970          min:       2 
     971          min_error: This field is too short (2 characters minimum) 
     972          max:       100 
     973          max_error: This field is too long (100 characters maximum) 
     974 
     975    fields: 
     976      name: 
     977        required: 
     978          msg:       The name field cannot be left blank 
     979        myStringValidator: 
     980      email: 
     981        required: 
     982          msg:       The email field cannot be left blank 
     983        myStringValidator: 
     984        sfEmailValidator: 
     985          email_error:  This email address is invalid 
     986      age: 
     987        sfNumberValidator 
     988          nan_error:    Please enter an integer 
     989          min:          0 
     990          min_error:    "You're not even born. How do you want to send a message?" 
     991          max:          120 
     992          max_error:    "Hey, grandma, aren't you too old to surf on the Internet?" 
     993      message: 
     994        required: 
     995          msg:          The message field cannot be left blank 
     996 
     997Validazione complessa 
     998--------------------- 
     999 
     1000Il file per la validazione soddisfa certamente la maggior parte dei bisogni, ma all'aumentare della complessita' potrebbe non bastare piu'. In tale caso, puoi restituire il metodo `validateXXX()` nell'azione, o trovare la soluzione al tuo problema nella sezione seguente. 
     1001 
     1002### Creare un validatore personalizzato 
     1003 
     1004Ogni validatore non è altro che una classa che estende `sfValidator`. Se quelli inclusi in symfony non soddisfano i tuoi bisogni, ne puoi creare uno personalizzato e posizionarlo in una delle cartelle `lib/` in modo che venga autocaricato. La sintassi è abbastanza semplice: viene chiamato il metodo `execute()` all'esecuzione del validatore. Puoi anche definire impostazioni dei default nel metodo `initialize()`. 
     1005 
     1006Il metodo `execute()` riceve come primo parametro il valore da validare, e l'errore da restituire come secondo. Entrambi vengono passati per riferimento, quindi puoi modificare il messaggio all'interno del metodo. 
     1007 
     1008Il metodo `initialize()` riceve il singleton ed un array di parametri dal file YAML. Esso deve prima di tutto chiamare il metodo `initialize()` del parent (`sfValidator`), quindi impostare i valori di default. 
     1009 
     1010Ogni validatore possiede un parameter holder accessibile tramite `$this->getParameterHolder()`. 
     1011 
     1012Ad esempio, se volessi creare un validatore `sfSpamValidator` per controllare che una stringa non contenga spam, inserisci il codice del Listato 10-31 in un file `sfSpamValidator.class.php`. Esso controlla che `$value` non contenga più di `max_url` volte la stringa '`http`'. 
     1013 
     1014Listato 10-31 - Creare un validatore personalizzato, in `lib/sfSpamValidator.class.php` 
     1015 
     1016    [php] 
     1017    class sfSpamValidator extends sfValidator 
     1018    { 
     1019      public function execute(&$value, &$error) 
     1020      { 
     1021        // For max_url=2, the regexp is /http.*http/is 
     1022        $re = '/'.implode('.*', array_fill(0, $this->getParameter('max_url') + 1, 'http')).'/is'; 
     1023 
     1024        if (preg_match($re, $value)) 
     1025        { 
     1026          $error = $this->getParameter('spam_error'); 
     1027 
     1028          return false; 
     1029        } 
     1030 
     1031        return true; 
     1032      } 
     1033 
     1034      public function initialize ($context, $parameters = null) 
     1035      { 
     1036        // Initialize parent 
     1037        parent::initialize($context); 
     1038 
     1039        // Set default parameters value 
     1040        $this->setParameter('max_url', 2); 
     1041        $this->setParameter('spam_error', 'This is spam'); 
     1042 
     1043        // Set parameters 
     1044        $this->getParameterHolder()->add($parameters); 
     1045 
     1046        return true; 
     1047      } 
     1048    } 
     1049 
     1050Appena il file è posizionato in una cartella su cui funziona l'autocaricamento (e la cache svuotata) puoi utilizzare il validatore, come mostrato nel Listato 10-33. 
     1051 
     1052Listato 10-33 - Utilizzare un validatore personalizzato, in `validate/send.yml` 
     1053 
     1054    fields: 
     1055      message: 
     1056        required: 
     1057          msg:          The message field cannot be left blank 
     1058        sfSpamValidator: 
     1059          max_url:      3 
     1060          spam_error:   Leave this site immediately, you filthy spammer! 
     1061 
     1062### Utilizzare la sintassi con array per le form 
     1063 
     1064PHP permette di usare una sintassi con array nelle form. Sia che tu scriva le tue form, sia che tu usi quelle generate dall'amministrazione di Propel (v. Capitolo 14), puoi avere del codice come quello del Listato 10-34. 
     1065 
     1066Listato 10-34 - Form con sintassi di array 
     1067 
     1068    [php] 
     1069    <label for="story[title]">Title:</label> 
     1070    <input type="text" name="story[title]" id="story[title]" value="default value" 
     1071           size="45" /> 
     1072 
     1073Utilizzare tale nome del campo input (con le parentesi quadre) in un file per la validazione generera' un errore di parsing. La soluzione in questo caso è quella di usare le parentesi graffe invece delle quadre nella sezione `fields`, come mostrato nel Listato 10-35, e symfony si occupera' del resto. 
     1074 
     1075Listato 10-35 - File per la validazione con sintassi di array 
     1076 
     1077    fields: 
     1078      story{title}: 
     1079        required:     Yes 
     1080 
     1081### Eseguire un validatore su un campo vuoto 
     1082 
     1083Potresti aver bisogno di eseguire una validazione su un campo non obbligatorio, od un valore vuoto. Ad esempio, ciò potrebbe succedere in una form dove un utente può (ma non è obbligato) cambiare la propria password, e in tale caso la deve confermare. 
     1084 
     1085Listato 10-36 - Esempio di file per la validazione per una form con due campi password 
     1086 
     1087    fields: 
     1088      password1: 
     1089      password2: 
     1090        sfCompareValidator: 
     1091          check:         password1 
     1092          compare_error: The two passwords do not match 
     1093 
     1094Il processo di validazione viene eseguito così: 
     1095 
     1096  * Se `password1 == null` e `password2 == null`: 
     1097 
     1098    * Il test `required` è ok 
     1099    * I validatori non vengono eseguiti 
     1100    * La form è valida 
     1101 
     1102  * Se `password2 == null` mentre `password1` no: 
     1103 
     1104    * Il test `required` è ok 
     1105    * I validatori non vengono eseguiti 
     1106    * La form è valida 
     1107 
     1108Potresti voler eseguire il validatore su `password2` se `password1` non è vuota. Fortunatamente i validatori di symfony gestiscono tale eventualita', grazie al parametro `group`. Quando un campo fa parte di un gruppo, il proprio validatore verrà eseguito se non è vuoto o se uno dei campi dello stesso gruppo non è vuoto. 
     1109 
     1110Quindi, se cambi la tua configurazione come quella mostrata nel Listato 10-37, il processo di validazione si comporterà correttamente. 
     1111 
     1112Listato 10-37 - Esempio di file per la validazione per una form con due campi password ed un gruppo 
     1113 
     1114    fields:c 
     1115      password1: 
     1116        group:           password_group 
     1117      password2: 
     1118        group:           password_group 
     1119        sfCompareValidator: 
     1120          check:         password1 
     1121          compare_error: The two passwords do not match 
     1122 
     1123Ora il processo di validazione si comporta cosi': 
     1124 
     1125  * Se `password1 == null` e `password2 == null`: 
     1126 
     1127    * Il test `required` è ok 
     1128    * I validatori non vengono eseguiti 
     1129    * La form è valida 
     1130 
     1131  * Se `password1 == null` e `password2 == 'foo'`: 
     1132 
     1133    * Il test `required` è ok 
     1134    * `password2` non è vuota, per cui il suo validatore viene eseguito e fallisce 
     1135    * Viene mostrato un messaggio di errore per `password2` 
     1136 
     1137  * Se `password1 == 'foo'` e `password2 == null`: 
     1138 
     1139    * Il test `required` è ok 
     1140    * `password1` non è vuota, per cui il validatore per `password2`, che fa parte dello stesso gruppo, viene eseguito e fallisce 
     1141    * Viene mostrato un messaggio di errore per `password2` 
     1142 
     1143  * Se `password1 == 'foo'` e `password2 == 'foo'`: 
     1144 
     1145    * Il test `required` è ok 
     1146    * `password2` non è vuota, per cui il suo validatore viene eseguito ed ha successo 
     1147    * La form è valida 
     1148 
     1149Sommario 
     1150-------- 
     1151 
     1152Scrivere form nelle template di symfony è un compito facilitato dagli helper e dalle loro opzioni. Quando disegni una form per modificare le proprieta' di un oggetto, gli helper degli oggetti semplificano notevolmente il tuo lavoro. I file per la validazione, gli helper per la validazione e la funzionalita' di ripopolamento delle form riducono notevolmente il tempo necessario alla costruzione di un robusto e user-friendly controllo sui valori dei campi. Ed anche nel caso in cui ti serva una validazione molto complessa, puoi scrivere il tuo validatore personalizzato o creare un metodo `validateXXX()` nell'azione. 
     1153 
     1154}}}