venerdì, agosto 30, 2013

PHP - Moduli HTML


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

Moduli HTML: come non reinventare la ruota

Una delle cose più comuni nello sviluppo di applicazioni web è di dover predisporre dei moduli per l'inserimento di dati da parte dell'utente.
Più di qualcuno si è cimentato nell'operazione di scrivere il codice HTML necessario, come ad esempio:

<form action="..." method="...">
<input type="text" name="id" value="12" />
</form>

Si tratta naturalmente di una pratica noiosa, passibile di errori, poco pratica rispetto alla manutenibilità del codice, ecc. e quindi, salvo casi particolari, da evitare.

Per non reinventare la ruota, esistono delle alternative:
  • usare librerie di classi già pronte che permettono di generare i moduli
  • usare framework che permettono generazione e gestione di moduli


Classi per la generazione di moduli

Tra le classi più popolari per la generazione di moduli, possiamo citare PEAR::HTML_QuickForm2 e UltimateForm.


HTML_QuickForm2

La documentazione di queste classi non è ancora presente, ma ci si può basare sul codice sorgente, sulla documentazione di HTML_QuickForm e sulla bozza di API.

L'esempio fornito con il pacchetto di installazione porta alla generazione di un modulo in cui compaiono gli elementi qui raffigurati:

Elementi generati con PEAR::HTML_QuickForm2

Fondamentalmente, per generare un modulo è necessario istanziare un oggetto di tipo HTML_QuickForm2, a cui dovremo agganciare i vari elementi, eventualmente raggruppati in fieldset.

require_once 'HTML/QuickForm2.php'; 
 
$form = new HTML_QuickForm2('picture'); 
 
$form->addDataSource(new HTML_QuickForm2_DataSource_Array(array(
    'hiddenId'        => $picture['id'], 
    'textDescription' => $picture['Description'], 
    'selCategory'     => $picture['Category_id'], 
    'textPath'        => $picture['Path'], 
    'textType'        => $picture['Type'], 
    'textWidth'       => $picture['Width'], 
    'textHeight'      => $picture['Height'], 
))); 

$form->addElement('hidden', 'hiddenId');
 
$fsImage = $form->addElement('fieldset')->setLabel('Immagine'); 
$fsImage->addElement( 
    'text', 'textDescription', array('style' => 'width: 300px;'), array('label' => 'Descrizione:') 
); 
$fsImage->addElement( 
    'select', 'selCategory', null, array('options' => $categories, 'label' => 'Categoria:') 
); 

$fsFile = $form->addElement('fieldset')->setLabel('File'); 
$fsFile->addElement( 
    'text', 'textPath', array('style' => 'width: 200px;'), array('label' => 'Percorso:') 
); 
$fsFile->addElement( 
    'text', 'textType', array('style' => 'width: 200px;'), array('label' => 'Tipo:') 
); 

$fsPhoto = $form->addElement('fieldset')->setLabel('Foto'); 
$fsPhoto->addElement( 
    'text', 'textWidth', array('style' => 'width: 200px; text-align: right'), array('label' => 'Larghezza:') 
); 
$fsPhoto->addElement( 
    'text', 'textHeight', array('style' => 'width: 200px; text-align: right'), array('label' => 'Altezza:') 
); 

$fsActions = $form->addElement('fieldset')->setLabel('Azioni'); 
$btnReset = $fsActions->addElement( 
    'reset', 'btnReset', array('value' => 'Reimposta valori') 
); 
$btnSubmit = $fsActions->addElement( 
    'submit', 'btnSubmit', array('value' => 'Salva') 
);

I dati da utilizzare per valorizzare i campi verranno probabilmente estratti da una base di dati, e dovremo decidere cosa fare alla ricezione del POST dell'utente. Il codice diventerà qualcosa di analogo al seguente:

<?php

/* model */

try
{
    /*** connect to SQLite database ***/
    $dbh = new PDO("sqlite2:pictures.sql.db");
   
    $sql = "SELECT id, Description FROM Category ORDER BY RANK;";
    
    $categories[' ']='--seleziona una categoria--';
       
    foreach ($dbh->query($sql, PDO::FETCH_ASSOC) as $row)
    {
      $categories[$row['id']] = $row['Description'];
    }

    $stmt = $dbh->prepare("SELECT * FROM Picture where id = :id");

    $stmt->bindParam(':id', $id);
    
    $id = $_GET['id'];

    if ($stmt->execute())
    {
      $picture = $stmt->fetch(PDO::FETCH_ASSOC);
    }
    
    
}
catch(PDOException $e)
{
    echo 'Error: ' . $e->getMessage() . "\n";
}


/* controller */
// vedi codice precedente

// decisione su cosa fare (se abbiamo avuto un post congeliamo il modulo)
if ('POST' == $_SERVER['REQUEST_METHOD'])
{
  $submittedData=$form->getValue(); 
  $fsActions->removeChild($btnReset); 
  $form->toggleFrozen(true); 
}

/* view */
?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <style type="text/css"> 
/* Set up custom font and form width */ 
body { 
    margin-left: 10px; 
    font-family: Arial,sans-serif; 
    font-size: small; 

 
.quickform { 
    min-width: 500px; 
    max-width: 600px; 
    width: 560px; 

 
/* Use default styles included with the package */ 
 
<?php readfile('data/quickform.css') ?> 
    </style> 
    <title>HTML_QuickForm2 example</title> 
  </head> 
  <body> 
<?php 
 
echo $form; 
?>

<?php if ($form->toggleFrozen()): ?>
  <p><a href="picture.php?id=<?php echo $id ?>">Modifica</a></p>
<?php endif ?>

<pre>
<?php print_r($picture) ?>
</pre>
</body> 
</html>

Si dovrebbe ottenere un modulo simile a questo:



Esercizi

  1. Integrare l'uso di HTML_QuickForm2 nell'applicazione di gestione delle immagini, con la possibilità di modificare descrizione e categoria di appartenenza delle fotografie memorizzate nella base di dati.
  2. Gestire in maniera corretta il POST (con un redirect a una richiesta effettuata con metodo GET).
  3. Integrare HTML_QuickForm2 nella propria gerarchia di classi, in modo che per l'oggetto Picture sia possibile avere un metodo generateForm() o equivalente.
  4. Provare a usare le funzioni di validazione lato client e lato server.
  5. Provare altre classi per la generazione di moduli, come UltimateForm.
  6. Dare un'occhiata alla documentazione relativa alla gestione dei moduli in symfony, in particolare l'appendice riguardante iwidget disponibili.

Nessun commento:

Posta un commento