Schema: Convalida dei dati
Una libreria pratica per la validazione e la normalizzazione delle strutture di dati rispetto a un determinato schema, con un'API intelligente e di facile comprensione.
Installazione:
Uso di base
Nella variabile $schema
abbiamo uno schema di validazione (cosa significa esattamente e come crearlo lo diremo
più avanti) e nella variabile $data
abbiamo una struttura di dati che vogliamo validare e normalizzare. Può
trattarsi, ad esempio, di dati inviati dall'utente tramite un'API, un file di configurazione, ecc.
Il compito è gestito dalla classe Nette\Schema\Processor, che elabora l'input e restituisce i dati normalizzati o lancia un'eccezione Nette\Schema\ValidationException in caso di errore.
Il metodo $e->getMessages()
restituisce un array di tutte le stringhe di messaggi e
$e->getMessageObjects()
restituisce tutti i messaggi come oggetti Nette\Schema\Message.
Definizione dello schema
Creiamo ora uno schema. Per definirlo, si usa la classe Nette\Schema\Expect. In pratica, si definiscono le
aspettative su come devono apparire i dati. Diciamo che i dati di input devono essere una struttura (ad esempio un array)
contenente elementi processRefund
di tipo bool e refundAmount
di tipo int.
La definizione dello schema appare chiara, anche se la si vede per la prima volta.
Inviamo i seguenti dati per la convalida:
L'output, cioè il valore $normalized
, è l'oggetto stdClass
. Se vogliamo che l'output sia un array,
aggiungiamo un cast allo schema Expect::structure([...])->castTo('array')
.
Tutti gli elementi della struttura sono opzionali e hanno un valore predefinito null
. Esempio:
Il fatto che il valore predefinito sia null
non significa che venga accettato nei dati di input
'processRefund' => null
. No, l'input deve essere booleano, cioè solo true
o false
.
Dovremmo consentire esplicitamente null
tramite Expect::bool()->nullable()
.
Un elemento può essere reso obbligatorio utilizzando Expect::bool()->required()
. Cambiamo il valore
predefinito in false
usando Expect::bool()->default(false)
o a breve usando
Expect::bool(false)
.
E se volessimo accettare 1
and 0
oltre ai booleani? Allora elenchiamo i valori consentiti, che
normalizzeremo anch'essi a booleani:
Ora si conoscono le basi di come viene definito lo schema e come si comportano i singoli elementi della struttura. Ora mostreremo quali sono gli altri elementi che possono essere utilizzati nella definizione di uno schema.
Tipi di dati: tipo()
Tutti i tipi di dati standard di PHP possono essere elencati nello schema:
E poi tutti i tipi supportati dai validatori tramite
Expect::type('scalar')
o Expect::scalar()
abbreviato. Sono accettati anche nomi di classi o interfacce,
ad esempio Expect::type('AddressEntity')
.
Si può anche usare la notazione unione:
Il valore predefinito è sempre null
, tranne che per array
e list
, dove è un array
vuoto. (Un elenco è un array indicizzato in ordine crescente di chiavi numeriche a partire da zero, cioè un array non
associativo).
Array di valori: arrayOf() listOf()
L'array è una struttura troppo generica, è più utile specificare esattamente quali elementi può contenere. Ad esempio, un array i cui elementi possono essere solo stringhe:
Il secondo parametro può essere utilizzato per specificare le chiavi (dalla versione 1.2):
L'elenco è un array indicizzato:
Il parametro può anche essere uno schema, quindi possiamo scrivere:
Il valore predefinito è un array vuoto. Se si specifica un valore predefinito, questo verrà unito ai dati passati. Questo
può essere disabilitato usando mergeDefaults(false)
(dalla versione 1.1).
Enumerazione: anyOf()
anyOf()
è un insieme di valori o schemi che un valore può essere. Ecco come scrivere un array di elementi che
possono essere 'a'
, true
, o null
:
Anche gli elementi dell'enumerazione possono essere schemi:
Il metodo anyOf()
accetta le varianti come parametri individuali, non come array. Per passargli un array di
valori, utilizzare l'operatore di spacchettamento anyOf(...$variants)
.
Il valore predefinito è null
. Utilizzare il metodo firstIsDefault()
per rendere il primo elemento il
valore predefinito:
Strutture
Le strutture sono oggetti con chiavi definite. Ciascuna di queste coppie chiave ⇒ valore viene definita „proprietà“:
Le strutture accettano array e oggetti e restituiscono oggetti stdClass
.
Per impostazione predefinita, tutte le proprietà sono opzionali e hanno un valore predefinito di null
. È
possibile definire proprietà obbligatorie utilizzando required()
:
Se non si vuole che vengano emesse proprietà con un valore predefinito, utilizzare skipDefaults()
:
Sebbene null
sia il valore predefinito della proprietà optional
, non è consentito nei dati di input
(il valore deve essere una stringa). Le proprietà che accettano null
sono definite con nullable()
:
L'array di tutte le proprietà della struttura viene restituito dal metodo getShape()
.
Per impostazione predefinita, non ci possono essere elementi extra nei dati di input:
Che possiamo cambiare con otherItems()
. Come parametro, specificheremo lo schema per ogni elemento extra:
È possibile creare una nuova struttura derivandola da un'altra utilizzando extend()
:
Schieramento
Un array con chiavi definite. Si applicano le stesse regole delle strutture.
È anche possibile definire un array indicizzato, noto come tupla:
Deprecazioni
È possibile deprecare una proprietà utilizzando il metodo deprecated([string $message])
. Gli avvisi di
deprecazione sono restituiti da $processor->getWarnings()
:
Intervalli: min() max()
Utilizzate min()
e max()
per limitare il numero di elementi degli array:
Per le stringhe, limitare la loro lunghezza:
Per i numeri, limitarne il valore:
Naturalmente, è possibile citare solo min()
, o solo max()
:
Espressioni regolari: pattern()
Utilizzando pattern()
, è possibile specificare un'espressione regolare a cui deve corrispondere l'intera stringa
di input (cioè come se fosse avvolta da caratteri ^
a $
):
Asserzioni personalizzate: assert()
È possibile aggiungere qualsiasi altra restrizione utilizzando assert(callable $fn)
.
Oppure
È possibile aggiungere la propria descrizione per ogni asserzione. Sarà parte del messaggio di errore.
Il metodo può essere richiamato più volte per aggiungere più vincoli. Può essere mescolato con le chiamate a
transform()
e castTo()
.
Trasformazione: transform()
I dati convalidati con successo possono essere modificati utilizzando una funzione personalizzata:
Il metodo può essere richiamato ripetutamente per aggiungere più trasformazioni. Può essere mescolato con le chiamate a
assert()
e castTo()
. Le operazioni saranno eseguite nell'ordine in cui sono state dichiarate:
Il metodo transform()
può trasformare e convalidare il valore contemporaneamente. Spesso è più semplice e meno
ridondante che concatenare transform()
e assert()
. A questo scopo, la funzione riceve un oggetto Context con un metodo addError()
, che può
essere usato per aggiungere informazioni sui problemi di validazione:
Casting: castTo()
I dati convalidati con successo possono essere lanciati:
Oltre ai tipi nativi di PHP, è possibile eseguire il cast su classi. Si distingue se si tratta di una classe semplice senza costruttore o di una classe con costruttore. Se la classe non ha un costruttore, ne viene creata un'istanza e tutti gli elementi della struttura vengono scritti nelle sue proprietà:
Se la classe ha un costruttore, gli elementi della struttura vengono passati come parametri al costruttore:
Il casting combinato con un parametro scalare crea un oggetto e passa il valore come unico parametro al costruttore:
Normalizzazione: before()
Prima della validazione vera e propria, i dati possono essere normalizzati con il metodo before()
. A titolo di
esempio, abbiamo un elemento che deve essere un array di stringhe (es. ['a', 'b', 'c']
), ma che riceve un input sotto
forma di stringa a b c
:
Mappatura a oggetti: from()
È possibile generare uno schema di struttura dalla classe. Esempio:
Sono supportate anche le classi anonime:
Poiché le informazioni ottenute dalla definizione della classe potrebbero non essere sufficienti, è possibile aggiungere uno schema personalizzato per gli elementi con il secondo parametro: