Creare form in PHP senza scrivere una riga di HTML

Una delle attività più ricorrenti per uno sviluppatore web è quello di creare form. Come immagino molti sanno, a lungo andare, diventa un compito piuttosto noioso, in cui ricorrono spesso la stessa tipologia di richieste.

Nonostante in rete si possano trovare numerose soluzioni a questo problema, ho deciso di svilupparne una mia perché nessuna di quelle che ho trovato si adattavano alle mie esigenze.

Le principali caratteristiche della mia soluzione sono:

  • definizione dei campi del form in XML
  • validazione dei dati
  • precompilazione dei campi
  • popolamento dei <select> da database
  • consente di replicare porzioni o l’intero form N volte senza duplicazioni di codice


UPDATE 17/01/2012: È disponibile l’ultima versione a questa pagina

Tecnologie coinvolte e requisiti

La classe principale è scritta in PHP e utilizza la libreria javascript Jquery assieme ad alcuni plugin per svolgere varie funzioni tra cui la validazione. Come già detto, lo schema di definizione del form deve essere scritto in XML.

Come requisiti lato server è necessario avere installato PHP 5 con l’estensione “SimpleXML” attiva (questa estensione è attiva di default).

Guida all’utilizzo

A questo link potete scaricare un pacchetto contenente tutto il necessario, alcuni esempi e un riassunto di tutti i campi e le opzioni disponibili.

Il form

Analizziamo per prima cosa la struttura del file XML di definizione del form.

<form>
	<action>index.php</action>
	<method>post</method>
	<id>frm_test</id>
	<class>frm_edit</class>
	<enctype>multipart/form-data</enctype>
	<page>
		<section>
			<field>
			...
			</field>
		...
		</section>
		...
	</page>
</form>

Il nodo principale è <form> e può contenere uno o più elementi <page> che a loro volta contengono le <section>. Le <page> non possono essere innestate tra loro, al contrario le <section> si.
I nodi che configurano il form hanno gli stessi nomi e significati degli attributi html. L’unico obbligatorio è <id>.

I campi di testo semplice

I campi del form sono rappresentati dal nodo <field> e possono essere inseriti solo sotto una <section>, ad esempio per un campo testo:

<form>
	<action>index.php</action>
	<method>post</method>
	<id>frm_test</id>
	<class>frm_edit</class>
	<enctype>multipart/form-data</enctype>
	<page>
		<section>
			<field>
				<id>surname</id>
				<type>text</type>
			</field>
		</section>
	</page>
</form>

più in generale:

<field>
	<id></id>				*
	<class></class>
	<label></label>
	<type>[text language=",hidden,password"][/text][/text]</type>	*
	<extra>[calendar,datemask]</extra>
	<required>1</required>
	<readonly>1</readonly>
	<value></value>
</field>

I due nodi con * sono obbligatori.

Spiegazione dei campi:

  • <id>: id dell’elemento
  • <class>: vanno indicate le eventuali classi CSS dell’elemento
  • <label>: etichetta associata all’elemento, se omessa viene utilizzato <id>
  • <type>: analogo al significato html
  • <extra>:
    • calendar: viene aggiunto un calendario per scegliere una data
    • datemask: l’inserimento dei dati è vincolato da una maschera apposita per la data
  • <required>: campo obbligatorio
  • <readonly>: campo in sola lettura
  • <value>: valore preimpostato del campo

I combobox

Un elemento particolarmente potente è il combobox. È possibile popolarlo in 3 modi: da xml, da database e da php. Per ora ci occuperemo dei primi due modi:

<field>
	<id>country</id>
	<type>select</type>
	<lookup>
		<table>country</table>
		<where>continent LIKE 'EU'</where>
		<orderby>name ASC</orderby>
		<id>code</id>
		<caption>name</caption>
		<showId>1</showId>
	</lookup>
	<values>
		<opt>
			<label>select</label>
			<value>0</value>
		</opt>
	</values>
	<value>0</value>
</field>

Nel nodo <lookup> si definisce la query per estrarre i dati:

  • <table>: nome della tabella
  • <where>: clausola where
  • <orderby>: clausola order by
  • <id>: campo da utilizzare per <option value=”XXX”>
  • <caption>: campo da utilizzare per <option>YYY</option>
  • <showId>: se mostrare anche l’id nella descrizione, ad es. <option value=”XXX”>XXX – YYY</option>

In questo caso i campi obbligatori sono table, id, caption.

Nel nodo <values> si definiscono staticamente le opzioni (<opt>) da mostrare:

  • <label>: valore da utilizzare per <option>YYY</option>
  • <value>: valore da utilizzare per <option value=”XXX”>

Altri componenti

Gli altri componenti restanti (textarea, checkbox, radio button) possono essere ricondotti alle due tipologie appena viste.

<field>
	<type>textarea</type>	*
	<id></id>		*
	<class></class>
	<label></label>
	<required>1</required>
	<readonly>1</readonly>
	<value></value>
</field>
 
<field>
	<type>radio</type>				*
	<id></id>					*
	<class></class>
	<label></label>
	<required>1</required>
	<readonly>1</readonly>
	<value></value>
	<values>					*
		<opt>					*
			<id></id>			*
			<label></label>			*
			<value></value>			*
		</opt>
		...
		<opt>
			<id></id>
			<label></label>
			<value></value>
		</opt>
		...
	</values>
</field>
 
<field>
	<type>checkbox</type>	*
	<id></id>		*
	<class></class>
	<label></label>
	<required>1</required>
	<readonly>1</readonly>
	<value></value>		*
</field>

Validazione

Una delle caratteristiche salienti di questa classe è, appunto, la validazione, che può essere di due tipi:
campo non nullo
campo valorizzato secondo una certa regola

Per il primo caso, abbiamo già visto l’elemento <required>1</required> che può essere inserito all’interno di ogni <field>.

Per il secondo caso, invece è stato introdotto l’elemento <validation> (anch’esso deve essere inserito all’interno del <field> interessato).
Sono a disposizione tutti i tipi di validazione forniti dal plugin Validation di Jquery (http://docs.jquery.com/Plugins/Validation). In particolare:

se il contenuto deve essere un numero:

<validation>number</validation>

se il contenuto deve essere una data:

<validation>date</validation>

se il contenuto deve essere un indirizzo email:

<validation>email</validation>

se il valore di un campo deve essere uguale a quello di un altro (es. conferma password):

<validation>
	<type>equalTo</type>
	<field>field_name</field>
</validation>

se il valore di un campo deve essere maggiore a quello di un altro:

<validation>
	<type>gt</type>
	<field>field_name</field>
</validation>

se il valore di un campo deve essere maggiore o uguale a quello di un altro:

<validation>
	<type>ge</type>
	<field>field_name</field>
</validation>

La validazione sarà effettuata sia prima dell’invio del form tramite javascript, sia dopo tramite PHP.

Creare un oggetto form

Creare un oggetto form è molto semplice:

$file = 'form01.xml';
$form = new FormBuilder($file);

l’unico parametro obbligatorio è la path del file xml.
Se nel vostro form è presente anche un combobox che legge i risultati dal database è necessario istanziare e passare come parametro anche un oggetto per il database:

$db = new Database('host','username','password','db_name');
$file = 'form01.xml';
$form = new FormBuilder($file, $db);

N.B. Non è indispensabile che venga passato un oggetto della classe Database. È possibile utilizzarne anche un’altra, a patto che questa possieda un metodo che risponda alla seguente interfaccia

public function fetchAll(string $query)

e che come output ritorni un array di array di questo genere:

Array
(
    [0] => Array
        (
            [id] => GB
            [caption] => Great Britain
        )
 
    [1] => Array
        (
            [id] => IT
            [caption] => Italy
        )
 
    [2] => Array
        (
            [id] => SM
            [caption] => San Marino
        )
 
)

Mostrare il form

Per mostrare il form è sufficiente il seguente comando:

echo $form->print_form();

Ecco un esempio di ciò che potrete ottenere:

Controllare se il form è valido

Dopo che il form è stato inviato, è possibile controllare se ha passato tutte le validazioni.
È bene tenere presente che, se i javascript sono attivati, la maggior parte delle validazioni sono eseguite prima dell’invio, quindi non è possibile inviare il form se le condizioni non sono soddisfatte. Nei casi in cui i javascript sono disattivati o per alcuni controlli particolari è indispensabile che le validazioni siano lato server.

È sufficiente il seguente controllo:

if(!empty($_POST) && $form->isValid())
{
	// success
}
else
{
	// failure
}

nel caso in cui i dati non siano validi, se non si prende nessun provvedimento, viene mostrato nuovamente il form con tutti i dati precedentemente inviati.

Configurazioni per creare un form di ricerca avanzata

Questa classe può rendere più semplice anche la creazione di form per la ricerca avanzata, cioè nei casi in cui per ogni campo è necessario definire una condizione di ricerca o un range di valori. Nell’immagine sottostante trovate un esempio del risultato finale:

I sorgenti di questo esempio sono nel pacchetto allegato nei file form02.php e form02.xml.

La struttura del file xml è molto simile a quella precedentemente vista, le differenze stanno negli elementi contenuti all’interno dei <field>.
Le direttive <required> e <validation> saranno ignorate, mentre viene introdotto l’elemento <search>.

Per la ricerca su un valore:

<search>
	<op>[eq,gt,ge,lt,le,like,not_like,all_str,all_num]</op>
</search>

L’elemento <search> può avere uno o più figli (in genere uno o due) di tipo <op>. All’interno di questo tag si definisce quale o quali operatori sono disponibili per il campo.
La classe mette a disposizione i più comuni:

eq =
gt >
ge >=
lt <
le <=
like equivalente al ‘LIKE’ in sql
not_like equivalente al ‘NOT LIKE’ in sql

poi due operatori che raggruppano i precedenti:

all_str include like e not_like
all_num include tutti gli operatori tranne like e not_like

Esempi:
con il seguente codice:

<field>
	<id>age</id>
	<type>text</type>
	<search>
		<op>eq</op>
	</search>
</field>

otterrete:

invece così facendo:

<field>
	<id>age</id>
	<type>text</type>
	<search>
		<op>all_num</op>
	</search>
</field>

avrete questo risultato:

Indicando un operatore singolo verrà forzato l’utilizzo di solo quella scelta, mentre utilizzando un operatore di raggruppamento si avrà la possibilità di scegliere una delle opzioni.

Nel caso in cui si voglia effettuare la ricerca su un range di valori, si devono indicare due operatori:

<search>
	<op>all_num</op>
	<op>all_num</op>
</search>

Ad esempio, volendo fare la ricerca su un intervallo di date:

<field>
	<id>date</id>
	<type>text</type>
	<extra>calendar</extra>
	<required>1</required>
	<validation>date</validation>
	<search>
		<op>all_num</op>
		<op>all_num</op>
	</search>
</field>

otterrete:

Dal lato PHP le differenze sono poche.

$db = new Database('host','username','password','db_name');
$file = 'form02.xml';
$form = new FormBuilder($file, $db);
 
if(!empty($_POST))
{
	$form->setValues($_POST);
}
 
echo $form->print_form(false,true);

Questa porzione di codice è tutto ciò che serve per mostrare il form di ricerca.
Le cose da notare sono tre:

  • nella clausola IF non è necessario controllare se il form è valido
  • con l’istruzione $form->setValues($_POST); si popola il form con i valori inviati, comprese le condizioni
  • nella chiamata al metodo print_form è necessario che sia passato come secondo parametro il valore true

Conclusioni

Come abbiamo visto, questa classe è ricca di funzionalità, versatile per diverse esigenze e pone una buona base per la generazione di form dinamici. È sempre in via di sviluppo e questa che ho mostrato è la prima versione stabile.

Demo

La demo è consultabile a questa pagina

UPDATE 17/01/2012: È disponibile l’ultima versione a questa pagina

Download

Il pacchetto completo è scaricabile QUI

6 pensieri su “Creare form in PHP senza scrivere una riga di HTML

  1. Buona giornata Andrea,
    complimenti per l’ottimo lavoro.

    Ho la possibilità di utilizzarlo in progetti commerciali?
    Bisogna acquistare una licenza d’uso?

    Claudio_

  2. Ciao, volevo chiederti una cosa. Io ho un form con 3 text box e uso il metodo post. Se compilo 2 text ed una la lascio vuota quando clicco su invia, nella pagina php successiva (collegata tramite post) mi da’ errore (ho messo in if di controllo). Come si risolve il problema?

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *