Validierung von Formularen
Erforderliche Steuerelemente
Steuerelemente werden mit der Methode setRequired()
als erforderlich markiert, deren Argument der Text der Fehlermeldung ist, die angezeigt wird, wenn der Benutzer sie nicht ausfüllt. Wenn kein Argument
angegeben wird, wird die Standard-Fehlermeldung verwendet.
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
Regeln
Mit der Methode addRule()
fügen wir den Steuerelementen Validierungsregeln hinzu. Der erste Parameter ist die
Regel, der zweite die Fehlermeldung und der dritte das Argument für die
Überprüfungsregel.
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password must be at least %d characters', 8);
Validierungsregeln werden nur dann überprüft, wenn der Benutzer das Element ausgefüllt hat.
Nette verfügt über eine Reihe von vordefinierten Regeln, deren Namen Konstanten der Klasse Nette\Forms\Form
sind. Wir können diese Regeln auf alle Elemente anwenden:
Konstante | Beschreibung | Argumente |
---|---|---|
Required |
alias von setRequired() |
– |
Filled |
alias von setRequired() |
– |
Blank |
darf nicht gefüllt werden | – |
Equal |
Wert ist gleich dem Parameter | mixed |
NotEqual |
Wert ist nicht gleich Parameter | mixed |
IsIn |
Wert ist gleich einem Element im Array | array |
IsNotIn |
Wert ist nicht gleich einem Element im Array | array |
Valid |
Eingabe besteht Validierung (für Bedingungen) | – |
Texteingaben
Für die Elemente addText()
, addPassword()
, addTextArea()
, addEmail()
,
addInteger()
, addFloat()
können auch einige der folgenden Regeln angewendet werden:
MinLength |
minimale Stringlänge | int |
MaxLength |
maximale Länge der Zeichenkette | int |
Length |
Länge im Bereich oder exakte Länge | Paar [int, int] oder int |
Email |
gültige E-Mail Adresse | – |
URL |
gültige URL | – |
Pattern |
entspricht regulärem Muster | string |
PatternInsensitive |
wie Pattern , aber Groß-/Kleinschreibung wird nicht berücksichtigt |
string |
Integer |
ganze Zahl | – |
Numeric |
Alias von Integer |
– |
Float |
Ganzzahl oder Fließkommazahl | – |
Min |
Minimum des Integer-Wertes | int|float |
Max |
Maximum des ganzzahligen Wertes | int|float |
Range |
Wert im Bereich | Paar [int|float, int|float] |
Die Regeln Integer
, Numeric
und Float
konvertieren den Wert automatisch in Ganzzahl
(bzw. Gleitkommazahl). Außerdem akzeptiert die Regel URL
auch eine Adresse ohne Schema (z. B.
nette.org
) und vervollständigt das Schema (https://nette.org
). Die Ausdrücke in Pattern
und PatternInsensitive
müssen für den gesamten Wert gültig sein, d. h. so, als ob er in die Zeichen ^
and $
eingeschlossen wäre.
Anzahl der Artikel
Für die Elemente addMultiUpload()
, addCheckboxList()
, addMultiSelect()
können Sie auch
die folgenden Regeln verwenden, um die Anzahl der ausgewählten Elemente oder hochgeladenen Dateien zu begrenzen:
MinLength |
Mindestanzahl | int |
MaxLength |
maximale Anzahl | int |
Length |
Anzahl im Bereich oder genaue Anzahl | Paare [int, int] oder int |
Datei hochladen
Für die Steuerelemente addUpload()
, addMultiUpload()
können auch die folgenden Regeln verwendet
werden:
MaxFileSize |
Maximale Dateigröße in Bytes | int |
MimeType |
MIME-Typ, akzeptiert Wildcards ('video/*' ) |
string|string[] |
Image |
hochgeladene Datei ist JPEG, PNG, GIF, WebP | – |
Pattern |
Dateiname entspricht regulärem Ausdruck | string |
PatternInsensitive |
wie Pattern , aber Groß-/Kleinschreibung wird nicht berücksichtigt |
string |
Für MimeType
und Image
ist die PHP-Erweiterung fileinfo
erforderlich. Ob eine Datei
oder ein Bild dem erforderlichen Typ entspricht, wird anhand ihrer Signatur erkannt. Die Integrität der gesamten Datei wird nicht
geprüft. Sie können herausfinden, ob ein Bild nicht beschädigt ist, indem Sie beispielsweise versuchen, es zu laden.
Fehlermeldungen
Alle vordefinierten Regeln außer Pattern
und PatternInsensitive
haben eine Standard-Fehlermeldung,
so dass sie weggelassen werden können. Wenn Sie jedoch alle benutzerdefinierten Meldungen übergeben und formulieren, wird das
Formular benutzerfreundlicher.
Sie können die Standardmeldungen in configuration ändern, indem
Sie die Texte im Array Nette\Forms\Validator::$messages
ändern oder den Übersetzer verwenden.
Die folgenden Platzhalter können im Text der Fehlermeldungen verwendet werden:
%d |
ersetzt schrittweise die Regeln nach den Argumenten |
%n$d |
ersetzt durch das n-te Regelargument |
%label |
ersetzt durch Feldbezeichnung (ohne Doppelpunkt) |
%name |
ersetzt durch den Feldnamen (z.B. name ) |
%value |
ersetzt durch den vom Benutzer eingegebenen Wert |
$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]);
Bedingungen
Neben den Validierungsregeln können auch Bedingungen festgelegt werden. Sie werden ähnlich wie Regeln gesetzt, jedoch
verwenden wir addRule()
anstelle von addCondition()
und lassen sie natürlich ohne Fehlermeldung stehen
(die Bedingung fragt nur):
$form->addPassword('password', 'Passwort:')
// wenn das Passwort nicht länger als 8 Zeichen ist ...
->addCondition($form::MaxLength, 8)
// ... dann muss es eine Zahl enthalten
->addRule($form::Pattern, 'Muss Zahl enthalten', '.*[0-9].*');
Die Bedingung kann mit einem anderen Element als dem aktuellen verknüpft werden, indem addConditionOn()
verwendet
wird. Der erste Parameter ist ein Verweis auf das Feld. Im folgenden Fall ist die E-Mail nur erforderlich, wenn das
Kontrollkästchen aktiviert ist (d. h. sein Wert ist true
):
$form->addCheckbox('newsletters', 'Newsletter versenden');
$form->addEmail('email', 'Email:')
// wenn das Kontrollkästchen aktiviert ist ...
->addConditionOn($form['newsletters'], $form::Equal, true)
// ... erfordern E-Mail
->setRequired('Füllen Sie Ihre E-Mail-Adresse aus');
Bedingungen können mit den Methoden elseCondition()
und endCondition()
zu komplexen Strukturen
gruppiert werden.
$form->addText(/* ... */)
->addCondition(/* ... */) // wenn die erste Bedingung erfüllt ist
->addConditionOn(/* ... */) // und die zweite Bedingung auch für ein anderes Element
->addRule(/* ... */) // erfordert diese Regel
->elseCondition() // wenn die zweite Bedingung nicht erfüllt ist
->addRule(/* ... */) // erfordert diese Regeln
->addRule(/* ... */)
->endCondition() // wir kehren zur ersten Bedingung zurück
->addRule(/* ... */);
In Nette ist es sehr einfach, auf die Erfüllung oder Nichterfüllung einer Bedingung auf der JavaScript-Seite mit der Methode
toggle()
zu reagieren, siehe Dynamisches JavaScript.
Verweis auf ein anderes Element
Als Argument für eine Regel oder Bedingung können Sie auch ein anderes Formularelement übergeben. Die Regel wird dann den
Wert verwenden, den der Benutzer später im Browser eingibt. Auf diese Weise kann z. B. dynamisch überprüft werden, ob das
Element password
dieselbe Zeichenfolge enthält wie das Element password_confirm
:
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
Benutzerdefinierte Regeln und Bedingungen
Manchmal kommen wir in eine Situation, in der die eingebauten Validierungsregeln in Nette nicht ausreichen und wir die Daten des Benutzers auf unsere eigene Weise validieren müssen. In Nette ist das sehr einfach!
Sie können einen beliebigen Callback als ersten Parameter an die Methoden addRule()
oder
addCondition()
übergeben. Der Callback akzeptiert das Element selbst als ersten Parameter und gibt einen booleschen
Wert zurück, der angibt, ob die Validierung erfolgreich war. Beim Hinzufügen einer Regel mit addRule()
können
zusätzliche Argumente übergeben werden, die dann als zweiter Parameter übergeben werden.
Der benutzerdefinierte Satz von Validatoren kann somit als Klasse mit statischen Methoden erstellt werden:
class MyValidators
{
// prüft, ob der Wert durch das Argument teilbar ist
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// zusätzliche Prüfer
}
}
Die Verwendung ist dann sehr einfach:
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'The value must be a multiple of %d',
8,
);
Benutzerdefinierte Validierungsregeln können auch zu JavaScript hinzugefügt werden. Die einzige Bedingung ist, dass die Regel
eine statische Methode sein muss. Ihr Name für den JavaScript-Validator wird durch Verkettung des Klassennamens ohne Backslashes
\
, the underscore _
und des Methodennamens gebildet. Schreiben Sie zum Beispiel
App\MyValidators::validateDivisibility
als AppMyValidators_validateDivisibility
und fügen Sie es dem
Objekt Nette.validators
hinzu:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
Ereignis onValidate
Nach dem Absenden des Formulars wird die Validierung durchgeführt, indem die einzelnen von addRule()
hinzugefügten Regeln überprüft und dann das Ereignis
onValidate
aufgerufen wird. Dessen Handler kann für zusätzliche Validierungen verwendet werden, in der Regel um die
korrekte Kombination von Werten in mehreren Formularelementen zu überprüfen.
Wenn ein Fehler festgestellt wird, wird er mit der Methode addError()
an das Formular weitergegeben. Diese kann
entweder für ein bestimmtes Element oder direkt für das Formular aufgerufen werden.
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('Diese Kombination ist nicht möglich.');
}
}
Verarbeitung von Fehlern
In vielen Fällen entdecken wir einen Fehler, wenn wir ein gültiges Formular verarbeiten, z. B. wenn wir einen neuen Eintrag
in die Datenbank schreiben und auf einen doppelten Schlüssel stoßen. In diesem Fall geben wir den Fehler mit der Methode
addError()
an das Formular zurück. Diese Methode kann entweder für ein bestimmtes Element oder direkt für das
Formular aufgerufen werden:
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.');
}
}
Wenn möglich, empfehlen wir, den Fehler direkt zum Formularelement hinzuzufügen, da er bei Verwendung des Standard-Renderers daneben angezeigt wird.
$form['date']->addError('Sorry, this date is already taken.');
Sie können addError()
wiederholt aufrufen, um mehrere Fehlermeldungen an ein Formular oder Element zu übergeben.
Sie erhalten sie mit getErrors()
.
Beachten Sie, dass $form->getErrors()
eine Zusammenfassung aller Fehlermeldungen zurückgibt, auch derjenigen,
die direkt an einzelne Elemente übergeben wurden, nicht nur direkt an das Formular. Fehlermeldungen, die nur an das Formular
übergeben werden, werden über $form->getOwnErrors()
abgerufen.
Ändern von Eingabewerten
Mit der Methode addFilter()
können wir den vom Benutzer eingegebenen Wert ändern. In diesem Beispiel werden wir
Leerzeichen in der Postleitzahl tolerieren und entfernen:
$form->addText('zip', 'Postleitzahl:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // Leerzeichen aus der Postleitzahl entfernen
})
->addRule($form::Pattern, 'Die Postleitzahl ist nicht fünfstellig', '\d{5}');
Der Filter ist zwischen den Validierungsregeln und -bedingungen eingefügt und hängt daher von der Reihenfolge der Methoden
ab, d. h. der Filter und die Regel werden in der gleichen Reihenfolge aufgerufen wie die Methoden addFilter()
und
addRule()
.
JavaScript-Überprüfung
Die Sprache der Validierungsregeln und -bedingungen ist mächtig. Auch wenn alle Konstruktionen sowohl server- als auch
clientseitig funktionieren, in JavaScript. Die Regeln werden in HTML-Attributen data-nette-rules
als JSON
übertragen. Die Validierung selbst wird von einem anderen Skript durchgeführt, das alle submit
Ereignisse des
Formulars abfängt, über alle Eingaben iteriert und entsprechende Validierungen durchführt.
Dieses Skript ist netteForms.js
, das von mehreren möglichen Quellen erhältlich ist:
Sie können das Skript direkt in die HTML-Seite aus dem CDN einbetten:
<script src="https://unpkg.com/nette-forms@3"></script>
Oder kopieren Sie es lokal in den öffentlichen Ordner des Projekts (z. B. von
vendor/nette/forms/src/assets/netteForms.min.js
):
<script src="/path/to/netteForms.min.js"></script>
Oder über npm installieren:
npm install nette-forms
Und dann laden und ausführen:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Alternativ können Sie es auch direkt aus dem Ordner vendor
laden:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
Dynamisches JavaScript
Sie möchten die Adressfelder nur dann anzeigen, wenn der Benutzer die Ware per Post verschicken möchte? Das ist kein Problem.
Der Schlüssel ist ein Paar von Methoden addCondition()
& toggle()
:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Dieser Code besagt, dass das HTML-Element #address-container
sichtbar wird, wenn die Bedingung erfüllt ist, d. h.
wenn das Kontrollkästchen markiert ist. Und vice versa. Wir platzieren also die Formularelemente mit der Adresse des Empfängers
in einem Container mit dieser ID, und wenn das Ankreuzfeld angeklickt wird, werden sie ein- oder ausgeblendet. Dies wird durch das
Skript netteForms.js
gesteuert.
Jeder Selektor kann als Argument an die Methode toggle()
übergeben werden. Aus historischen Gründen wird eine
alphanumerische Zeichenkette ohne andere Sonderzeichen als Element-ID behandelt, so als ob ihr das #
character. The
second optional parameter allows us to reverse the behavior, i.e. if we used toggle('#address-container', false)
vorangestellt wäre. Das Element würde nur angezeigt werden, wenn das Kontrollkästchen nicht angekreuzt ist.
Die Standardimplementierung von JavaScript ändert die Eigenschaft hidden
für Elemente. Wir können das Verhalten
jedoch leicht ändern, indem wir beispielsweise eine Animation hinzufügen. Überschreiben Sie einfach die Methode
Nette.toggle
in JavaScript mit einer benutzerdefinierten Lösung:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
Deaktivieren der Validierung
In bestimmten Fällen müssen Sie die Gültigkeitsprüfung deaktivieren. Wenn eine Submit-Schaltfläche nach dem Absenden keine
Validierung durchführen soll (z. B. Abbrechen oder Vorschau), können Sie die Validierung durch den Aufruf von
$submit->setValidationScope([])
deaktivieren. Sie können das Formular auch teilweise validieren, indem Sie
Elemente angeben, die validiert werden sollen.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Validiert das gesamte Formular
$form->addSubmit('send2')
->setValidationScope([]); // Überprüft nichts
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Prüft nur das Feld 'name'
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Validiert nur das Feld 'age'
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Validiert den 'details'-Container
Das Ereignis onValidate auf dem Formular wird immer aufgerufen und wird von
setValidationScope
nicht beeinflusst. onValidate
Ereignis auf dem Container wird nur aufgerufen, wenn
dieser Container für eine Teilvalidierung angegeben ist.