Validation des formulaires
Contrôles obligatoires
Les contrôles sont marqués comme obligatoires par la méthode setRequired()
, dont l'argument est le texte du message d'erreur qui sera affiché si l'utilisateur ne le remplit pas. Si aucun argument n'est
donné, le message d'erreur par défaut est utilisé.
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
Règles
Nous ajoutons des règles de validation aux contrôles avec la méthode addRule()
. Le premier paramètre est la
règle, le deuxième est le message d'erreur, et le troisième est l'argument de la règle de
validation.
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password must be at least %d characters', 8);
**Les règles de validation ne sont vérifiées que si l'utilisateur a rempli l'élément.
Nette est livré avec un certain nombre de règles prédéfinies dont les noms sont des constantes de la classe
Nette\Forms\Form
. Nous pouvons appliquer ces règles à tous les éléments :
constante | description | arguments |
---|---|---|
Required |
alias de setRequired() |
– |
Filled |
alias de setRequired() |
– |
Blank |
ne doit pas être rempli | – |
Equal |
la valeur est égale au paramètre | mixed |
NotEqual |
la valeur n'est pas égale au paramètre | mixed |
IsIn |
la valeur est égale à un élément du tableau | array |
IsNotIn |
la valeur n'est égale à aucun élément du tableau | array |
Valid |
L'entrée passe la validation (pour les conditions) | – |
Entrées de texte
Pour les éléments addText()
, addPassword()
, addTextArea()
, addEmail()
,
addInteger()
, addFloat()
, certaines des règles suivantes peuvent également être appliquées :
MinLength |
longueur minimale de la chaîne | int |
MaxLength |
longueur maximale de la chaîne de caractères | int |
Length |
longueur dans l'intervalle ou longueur exacte | paire [int, int] ou int |
Email |
adresse électronique valide | – |
URL |
URL valide | – |
Pattern |
correspond à un modèle régulier | string |
PatternInsensitive |
comme Pattern , mais insensible à la casse |
string |
Integer |
nombre entier | – |
Numeric |
alias de Integer |
– |
Float |
nombre entier ou à virgule flottante | – |
Min |
minimum de la valeur entière | int|float |
Max |
maximum de la valeur entière | int|float |
Range |
valeur dans l'intervalle | paire [int|float, int|float] |
Les règles Integer
, Numeric
et Float
convertissent automatiquement la valeur en nombre
entier (ou flottant respectivement). En outre, la règle URL
accepte également une adresse sans schéma (par exemple
nette.org
) et complète le schéma (https://nette.org
). Les expressions de Pattern
et
PatternInsensitive
doivent être valables pour la valeur entière, c'est-à-dire comme si elle était enveloppée
dans les caractères ^
and $
.
Nombre d'articles
Pour les éléments addMultiUpload()
, addCheckboxList()
, addMultiSelect()
vous pouvez
également utiliser les règles suivantes pour limiter le nombre d'éléments sélectionnés ou de fichiers téléchargés :
MinLength
| nombre minimum | | nombre maximum int
MaxLength |
nombre maximum int |
|
Length |
nombre dans l'intervalle ou nombre exact | paires [int, int] ou int |
Téléchargement de fichiers
Pour les contrôles addUpload()
, addMultiUpload()
, les règles suivantes peuvent également être
utilisées :
MaxFileSize |
taille maximale du fichier en octets | int |
MimeType
| type MIME, accepte les caractères génériques ('video/*'
) | type MIME, accepte les
caractères génériques ( ) | type MIME, accepte les caractères génériques ( ) string\|string[]
Image |
le fichier téléchargé est un JPEG, PNG, GIF, WebP | – |
Pattern |
le nom du fichier correspond à une expression régulière | string |
PatternInsensitive |
comme Pattern , mais insensible à la casse |
string |
Les sites MimeType
et Image
nécessitent l'extension PHP fileinfo
. Le fait qu'un fichier
ou une image soit du type requis est détecté par sa signature. L'intégrité de l'ensemble du fichier n'est pas vérifiée. Vous
pouvez savoir si une image n'est pas corrompue, par exemple en essayant de la charger.
Messages d'erreur
Toutes les règles prédéfinies, à l'exception de Pattern
et PatternInsensitive
, ont un message
d'erreur par défaut ; elles peuvent donc être omises. Toutefois, en passant et en formulant tous les messages personnalisés,
vous rendrez le formulaire plus convivial.
Vous pouvez changer les messages par défaut dans configuration, en
modifiant les textes dans le tableau Nette\Forms\Validator::$messages
ou en utilisant translator.
Les caractères de remplacement suivants peuvent être utilisés dans le texte des messages d'erreur :
%d |
remplace progressivement les règles après les arguments |
%n$d |
remplace par le nième argument de règle |
%label |
remplace par le libellé du champ (sans les deux points) |
%name |
remplace par le nom du champ (par exemple name ) |
%value |
remplace par la valeur entrée par l'utilisateur |
$form->addText('name', 'Name:')
->setRequired('Please fill in %label');
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);
Conditions
Outre les règles de validation, il est possible de définir des conditions. Elles sont définies de la même manière que les
règles, mais nous utilisons addRule()
au lieu de addCondition()
et, bien sûr, nous ne laissons pas de
message d'erreur (la condition demande simplement) :
$form->addPassword('password', 'Password:')
// si le mot de passe ne dépasse pas 8 caractères ...
->addCondition($form::MaxLength, 8)
// ... alors il doit contenir un nombre
->addRule($form::Pattern, 'Must contain number', '.*[0-9].*');
La condition peut être liée à un élément différent de l'élément actuel en utilisant addConditionOn()
. Le
premier paramètre est une référence au champ. Dans le cas suivant, l'e-mail ne sera requis que si la case est cochée
(c'est-à-dire si sa valeur est true
) :
$form->addCheckbox('newsletters', 'send me newsletters');
$form->addEmail('email', 'Email:')
// si la case est cochée ...
->addConditionOn($form['newsletters'], $form::Equal, true)
// ... nécessite un email
->setRequired('Remplissez votre adresse e-mail');
Les conditions peuvent être regroupées en structures complexes avec les méthodes elseCondition()
et
endCondition()
.
$form->addText(/* ... */)
->addCondition(/* ... */) // si la première condition est remplie
->addConditionOn(/* ... */) // et la deuxième condition sur un autre élément aussi
->addRule(/* ... */) // nécessite cette règle
->elseCondition() // si la deuxième condition n'est pas remplie
->addRule(/* ... */) // nécessite ces règles
->addRule(/* ... */)
->endCondition() // on revient à la première condition
->addRule(/* ... */);
Dans Nette, il est très facile de réagir à la réalisation ou non d'une condition du côté JavaScript en utilisant la
méthode toggle()
, voir Dynamic JavaScript.
Référence à un autre élément
En tant qu'argument d'une règle ou d'une condition, vous pouvez également transmettre un autre élément de formulaire. La
règle utilisera alors la valeur introduite ultérieurement par l'utilisateur dans le navigateur. Cela peut être utilisé, par
exemple, pour valider dynamiquement que l'élément password
contient la même chaîne de caractères que l'élément
password_confirm
:
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
Règles et conditions personnalisées
Parfois, nous nous trouvons dans une situation où les règles de validation intégrées dans Nette ne sont pas suffisantes et nous devons valider les données de l'utilisateur à notre manière. Avec Nette, c'est très facile !
Vous pouvez passer n'importe quel callback comme premier paramètre aux méthodes addRule()
ou
addCondition()
. La callback accepte l'élément lui-même comme premier paramètre et renvoie une valeur booléenne
indiquant si la validation a réussi. Lors de l'ajout d'une règle à l'aide de addRule()
, il est possible de
transmettre des arguments supplémentaires, qui sont ensuite transmis comme deuxième paramètre.
L'ensemble personnalisé de validateurs peut donc être créé comme une classe avec des méthodes statiques :
class MyValidators
{
// teste si la valeur est divisible par l'argument
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// validateurs supplémentaires
}
}
L'utilisation est alors très simple :
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'The value must be a multiple of %d',
8,
);
Les règles de validation personnalisées peuvent également être ajoutées à JavaScript. La seule exigence est que la règle
doit être une méthode statique. Son nom pour le validateur JavaScript est créé en concaténant le nom de la classe sans les
barres obliques inversées \
, the underscore _
, et le nom de la méthode. Par exemple, écrivez
App\MyValidators::validateDivisibility
sous la forme AppMyValidators_validateDivisibility
et ajoutez-la
à l'objet Nette.validators
:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
Événement onValidate
Après l'envoi du formulaire, la validation est effectuée en vérifiant les règles individuelles ajoutées par
addRule()
, puis en appelant l'événement
onValidate
. Son gestionnaire peut être utilisé pour une validation supplémentaire, généralement pour vérifier
la combinaison correcte de valeurs dans plusieurs éléments du formulaire.
Si une erreur est détectée, elle est transmise au formulaire à l'aide de la méthode addError()
. Celle-ci peut
être appelée soit sur un élément spécifique, soit directement sur le formulaire.
protected function createComponentSignInForm(): Form
{
$form = new Form;
// ...
$form->onValidate[] = [$this, 'validateSignInForm'];
return $form;
}
public function validateSignInForm(Form $form, \stdClass $data): void
{
if ($data->foo > 1 && $data->bar > 5) {
$form->addError('Cette combinaison n'est pas possible.');
}
}
Erreurs de traitement
Dans de nombreux cas, nous découvrons une erreur lors du traitement d'un formulaire valide, par exemple lorsque nous écrivons
une nouvelle entrée dans la base de données et que nous rencontrons un doublon de clé. Dans ce cas, nous transmettons l'erreur
au formulaire à l'aide de la méthode addError()
. Cette méthode peut être appelée soit sur un élément
spécifique, soit directement sur le formulaire :
try {
$data = $form->getValues();
$this->user->login($data->username, $data->password);
$this->redirect('Home:');
} catch (Nette\Security\AuthenticationException $e) {
if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
$form->addError('Invalid password.');
}
}
Si possible, nous recommandons d'ajouter l'erreur directement à l'élément de formulaire, car elle apparaîtra à côté de celui-ci lors de l'utilisation du moteur de rendu par défaut.
$form['date']->addError('Sorry, this date is already taken.');
Vous pouvez appeler addError()
à plusieurs reprises pour transmettre plusieurs messages d'erreur à un formulaire
ou à un élément. Vous les obtenez avec getErrors()
.
Notez que $form->getErrors()
renvoie un résumé de tous les messages d'erreur, même ceux transmis directement
aux éléments individuels, et pas seulement ceux transmis directement au formulaire. Les messages d'erreur passés uniquement au
formulaire sont récupérés via $form->getOwnErrors()
.
Modification des valeurs d'entrée
En utilisant la méthode addFilter()
, nous pouvons modifier la valeur saisie par l'utilisateur. Dans cet exemple,
nous allons tolérer et supprimer les espaces dans le code postal :
$form->addText('zip', 'Postcode:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // supprime les espaces du code postal
})
->addRule($form::Pattern, 'Le code postal n'est pas composé de cinq chiffres', '\d{5}');
Le filtre est inclus entre les règles et les conditions de validation et dépend donc de l'ordre des méthodes, c'est-à-dire
que le filtre et la règle sont appelés dans le même ordre que celui des méthodes addFilter()
et
addRule()
.
Validation JavaScript
Le langage des règles et conditions de validation est puissant. Même si toutes les constructions fonctionnent aussi bien du
côté serveur que du côté client, en JavaScript. Les règles sont transférées dans des attributs HTML
data-nette-rules
sous forme de JSON. La validation elle-même est gérée par un autre script, qui s'accroche à tous
les événements du formulaire submit
, itère sur toutes les entrées et exécute les validations respectives.
Ce script est netteForms.js
, qui est disponible à partir de plusieurs sources possibles :
Vous pouvez intégrer le script directement dans la page HTML à partir du CDN :
<script src="https://unpkg.com/nette-forms@3"></script>
Ou le copier localement dans le dossier public du projet (par exemple à partir de
vendor/nette/forms/src/assets/netteForms.min.js
) :
<script src="/path/to/netteForms.min.js"></script>
Ou installer via npm:
npm install nette-forms
Et ensuite charger et exécuter :
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Sinon, vous pouvez le charger directement depuis le dossier vendor
:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
JavaScript dynamique
Vous souhaitez afficher les champs d'adresse uniquement si l'utilisateur choisit d'envoyer les marchandises par la poste ?
Aucun problème. La clé est une paire de méthodes addCondition()
& toggle()
:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Ce code indique que lorsque la condition est remplie, c'est-à-dire lorsque la case est cochée, l'élément HTML
#address-container
sera visible. Et vice versa. Ainsi, nous plaçons les éléments de formulaire contenant l'adresse
du destinataire dans un conteneur avec cet ID, et lorsque la case à cocher est activée, ils sont cachés ou affichés. Cette
opération est gérée par le script netteForms.js
.
Tout sélecteur peut être transmis comme argument à la méthode toggle()
. Pour des raisons historiques, une
chaîne alphanumérique ne comportant aucun autre caractère spécial est traitée comme un identifiant d'élément, comme si elle
était précédée de l'adresse #
character. The second optional parameter allows us to reverse the behavior, i.e. if
we used toggle('#address-container', false)
. L'élément ne serait affiché que si la case à cocher n'était pas
cochée.
L'implémentation JavaScript par défaut modifie la propriété hidden
pour les éléments. Toutefois, nous
pouvons facilement modifier le comportement, par exemple en ajoutant une animation. Il suffit de remplacer la méthode
Nette.toggle
en JavaScript par une solution personnalisée :
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
Désactiver la validation
Dans certains cas, vous devez désactiver la validation. Si un bouton d'envoi n'est pas censé exécuter la validation après
l'envoi (par exemple le bouton Annulation ou Aperçu), vous pouvez désactiver la validation en appelant
$submit->setValidationScope([])
. Vous pouvez également valider partiellement le formulaire en spécifiant les
éléments à valider.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Valide l'ensemble du formulaire
$form->addSubmit('send2')
->setValidationScope([]); // Ne valide rien.
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Ne valide que le champ 'name'.
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Valide uniquement le champ 'age'.
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Valide le conteneur 'details'.
L'événement onValidate sur le formulaire est toujours invoqué et n'est pas affecté par
l'appel setValidationScope
. L'événement onValidate
sur le conteneur est invoqué uniquement lorsque ce
conteneur est spécifié pour la validation partielle.