Επικύρωση φορμών
Απαιτούμενοι έλεγχοι
Τα στοιχεία ελέγχου χαρακτηρίζονται ως υποχρεωτικά με τη μέθοδο
setRequired()
, της οποίας το όρισμα είναι το κείμενο του μηνύματος σφάλματος που θα εμφανιστεί αν ο χρήστης
δεν το συμπληρώσει. Εάν δεν δοθεί κανένα όρισμα, χρησιμοποιείται το
προεπιλεγμένο μήνυμα σφάλματος.
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
Κανόνες
Προσθέτουμε κανόνες επικύρωσης σε στοιχεία ελέγχου με τη μέθοδο
addRule()
. Η πρώτη παράμετρος είναι ο κανόνας, η δεύτερη είναι το μήνυμα σφάλματος και η τρίτη είναι το όρισμα του
κανόνα επικύρωσης.
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password must be at least %d characters', 8);
Οι κανόνες επαλήθευσης ελέγχονται μόνο αν ο χρήστης συμπλήρωσε το στοιχείο.
Η Nette διαθέτει έναν αριθμό προκαθορισμένων κανόνων, τα ονόματα των
οποίων είναι σταθερές της κλάσης Nette\Forms\Form
. Μπορούμε να
εφαρμόσουμε αυτούς τους κανόνες σε όλα τα στοιχεία:
σταθερά | περιγραφή | επιχειρήματα |
---|---|---|
Required |
ψευδώνυμο του setRequired() |
– |
Filled |
ψευδώνυμο του setRequired() |
– |
Blank |
δεν πρέπει να συμπληρωθεί | – |
Equal |
η τιμή είναι ίση με την παράμετρο | mixed |
NotEqual |
η τιμή δεν είναι ίση με την παράμετρο | mixed |
IsIn |
η τιμή είναι ίση με κάποιο στοιχείο του πίνακα | array |
IsNotIn |
η τιμή δεν είναι ίση με κάποιο στοιχείο του πίνακα | array |
Valid |
η είσοδος περνάει την επικύρωση (για τις συνθήκες) | – |
Είσοδοι κειμένου
Για τα στοιχεία addText()
, addPassword()
, addTextArea()
,
addEmail()
, addInteger()
, addFloat()
μπορούν επίσης να
εφαρμοστούν ορισμένοι από τους ακόλουθους κανόνες:
MinLength |
ελάχιστο μήκος συμβολοσειράς | int |
MaxLength |
μέγιστο μήκος συμβολοσειράς | int |
Length |
μήκος στο εύρος ή ακριβές μήκος | ζεύγος [int, int] ή int |
Email |
έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου | – |
URL |
έγκυρη διεύθυνση URL | – |
Pattern |
ταιριάζει με κανονικό μοτίβο | string |
PatternInsensitive |
όπως το Pattern , αλλά χωρίς να λαμβάνεται υπόψη η πεζότητα |
string |
Integer |
ακέραιος αριθμός | – |
Numeric |
ψευδώνυμο του Integer |
– |
Float |
ακέραιος ή αριθμός κινητής υποδιαστολής | – |
Min |
ελάχιστο της ακέραιης τιμής | int|float |
Max |
μέγιστο της ακέραιης τιμής | int|float |
Range |
τιμή στο εύρος | ζεύγος [int|float, int|float] |
Οι κανόνες Integer
, Numeric
και Float
μετατρέπουν
αυτόματα την τιμή σε ακέραιο (ή float αντίστοιχα). Επιπλέον, ο κανόνας
URL
δέχεται επίσης μια διεύθυνση χωρίς σχήμα (π.χ. nette.org
)
και συμπληρώνει το σχήμα (https://nette.org
). Οι εκφράσεις στους κανόνες
Pattern
και PatternInsensitive
πρέπει να ισχύουν για ολόκληρη την
τιμή, δηλαδή σαν να ήταν τυλιγμένη στους χαρακτήρες ^
and
$
.
Αριθμός στοιχείων
Για τα στοιχεία addMultiUpload()
, addCheckboxList()
, addMultiSelect()
μπορείτε επίσης να χρησιμοποιήσετε τους ακόλουθους κανόνες για να
περιορίσετε τον αριθμό των επιλεγμένων στοιχείων ή των ανεβασμένων
αρχείων:
MinLength |
ελάχιστος αριθμός | int |
MaxLength |
μέγιστος αριθμός | int |
Length |
αριθμός σε εύρος ή ακριβής αριθμός | ζεύγη [int, int] ή int |
Ανέβασμα αρχείου
Για τους ελέγχους addUpload()
, addMultiUpload()
μπορούν επίσης να
χρησιμοποιηθούν οι ακόλουθοι κανόνες:
MaxFileSize |
μέγιστο μέγεθος αρχείου σε bytes | int |
MimeType |
τύπος MIME, δέχεται μπαλαντέρ ('video/*' ) |
string|string[] |
Image |
το ανεβασμένο αρχείο είναι JPEG, PNG, GIF, WebP | – |
Pattern |
το όνομα του αρχείου ταιριάζει με κανονική έκφραση | string |
PatternInsensitive |
όπως το Pattern , αλλά χωρίς να λαμβάνεται υπόψη η πεζότητα |
string |
Τα MimeType
και Image
απαιτούν την επέκταση PHP fileinfo
. Το
αν ένα αρχείο ή μια εικόνα είναι του απαιτούμενου τύπου ανιχνεύεται
από την υπογραφή του. Η ακεραιότητα ολόκληρου του αρχείου δεν
ελέγχεται. Μπορείτε να διαπιστώσετε αν μια εικόνα δεν είναι
κατεστραμμένη, για παράδειγμα, προσπαθώντας να τη
φορτώσετε.
Μηνύματα σφάλματος
Όλοι οι προκαθορισμένοι κανόνες εκτός από τους Pattern
και
PatternInsensitive
έχουν ένα προεπιλεγμένο μήνυμα σφάλματος, οπότε
μπορούν να παραλειφθούν. Ωστόσο, περνώντας και διατυπώνοντας όλα τα
προσαρμοσμένα μηνύματα, θα κάνετε τη φόρμα πιο φιλική προς το χρήστη.
Μπορείτε να αλλάξετε τα προεπιλεγμένα μηνύματα στο configuration, τροποποιώντας τα κείμενα στον
πίνακα Nette\Forms\Validator::$messages
ή χρησιμοποιώντας τον μεταφραστή.
Τα ακόλουθα μπαλαντέρ μπορούν να χρησιμοποιηθούν στο κείμενο των μηνυμάτων σφάλματος:
%d |
αντικαθιστά σταδιακά τους κανόνες μετά τα επιχειρήματα |
%n$d |
αντικαθιστά με το νιοστό όρισμα του κανόνα |
%label |
αντικαθιστά με την ετικέτα πεδίου (χωρίς άνω και κάτω τελεία) |
%name |
αντικαθιστά με το όνομα του πεδίου (π.χ. name ) |
%value |
αντικαθιστά με την τιμή που εισάγει ο χρήστης |
$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]);
Συνθήκες
Εκτός από τους κανόνες επικύρωσης, μπορούν να οριστούν και συνθήκες.
Ορίζονται όπως και οι κανόνες, ωστόσο χρησιμοποιούμε το addRule()
αντί του addCondition()
και φυσικά, το αφήνουμε χωρίς μήνυμα σφάλματος
(η συνθήκη απλώς ρωτάει):
$form->addPassword('password', 'Password:')
// εάν ο κωδικός πρόσβασης δεν υπερβαίνει τους 8 χαρακτήρες ...
->addCondition($form::MaxLength, 8)
// ... τότε πρέπει να περιέχει έναν αριθμό
->addRule($form::Pattern, 'Must contain number', '.*[0-9].*');
Η συνθήκη μπορεί να συνδεθεί με ένα διαφορετικό στοιχείο από το
τρέχον χρησιμοποιώντας το addConditionOn()
. Η πρώτη παράμετρος είναι
μια αναφορά στο πεδίο. Στην ακόλουθη περίπτωση, το email θα απαιτείται
μόνο εάν το πλαίσιο ελέγχου είναι επιλεγμένο (δηλαδή η τιμή του είναι
true
):
$form->addCheckbox('newsletters', 'send me newsletters');
$form->addEmail('email', 'Email:')
// αν το πλαίσιο ελέγχου είναι επιλεγμένο ...
->addConditionOn($form['newsletters'], $form::Equal, true)
// ... απαιτούν email
->setRequired('Fill your email address');
Οι συνθήκες μπορούν να ομαδοποιηθούν σε σύνθετες δομές με τις
μεθόδους elseCondition()
και endCondition()
.
$form->addText(/* ... */)
->addCondition(/* ... */) // εάν πληρούται η πρώτη προϋπόθεση
->addConditionOn(/* ... */) // και η δεύτερη συνθήκη σε ένα άλλο στοιχείο επίσης
->addRule(/* ... */) // απαιτούν αυτόν τον κανόνα
->elseCondition() // αν η δεύτερη συνθήκη δεν ικανοποιείται
->addRule(/* ... */) // απαιτεί αυτούς τους κανόνες
->addRule(/* ... */)
->endCondition() // επιστρέφουμε στην πρώτη συνθήκη
->addRule(/* ... */);
Στη Nette, είναι πολύ εύκολο να αντιδράσετε στην εκπλήρωση ή όχι μιας
συνθήκης από την πλευρά της JavaScript χρησιμοποιώντας τη μέθοδο
toggle()
, βλέπε Δυναμική JavaScript.
Αναφορά σε άλλο στοιχείο
Ως όρισμα για έναν κανόνα ή συνθήκη, μπορείτε επίσης να περάσετε ένα
άλλο στοιχείο της φόρμας. Ο κανόνας θα χρησιμοποιήσει τότε την τιμή που
θα εισαχθεί αργότερα από τον χρήστη στο πρόγραμμα περιήγησης. Αυτό
μπορεί να χρησιμοποιηθεί, για παράδειγμα, για τη δυναμική επικύρωση
ότι το στοιχείο password
περιέχει την ίδια συμβολοσειρά με το
στοιχείο password_confirm
:
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
Προσαρμοσμένοι κανόνες και προϋποθέσεις
Μερικές φορές μπαίνουμε σε μια κατάσταση όπου οι ενσωματωμένοι κανόνες επικύρωσης της Nette δεν είναι αρκετοί και πρέπει να επικυρώσουμε τα δεδομένα από τον χρήστη με τον δικό μας τρόπο. Στη Nette αυτό είναι πολύ εύκολο!
Μπορείτε να περάσετε οποιοδήποτε callback ως πρώτη παράμετρο στις
μεθόδους addRule()
ή addCondition()
. Το callback δέχεται το ίδιο το
στοιχείο ως πρώτη παράμετρο και επιστρέφει μια boolean τιμή που δείχνει αν
η επικύρωση ήταν επιτυχής. Κατά την προσθήκη ενός κανόνα με τη χρήση
της μεθόδου addRule()
, μπορούν να περάσουν επιπλέον ορίσματα, τα
οποία στη συνέχεια περνούν ως δεύτερη παράμετρος.
Το προσαρμοσμένο σύνολο επικυρωτών μπορεί έτσι να δημιουργηθεί ως κλάση με στατικές μεθόδους:
class MyValidators
{
// ελέγχει αν η τιμή διαιρείται με το όρισμα
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// πρόσθετοι επικυρωτές
}
}
Η χρήση είναι τότε πολύ απλή:
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'The value must be a multiple of %d',
8,
);
Μπορούν επίσης να προστεθούν προσαρμοσμένοι κανόνες επικύρωσης σε
JavaScript. Η μόνη απαίτηση είναι ότι ο κανόνας πρέπει να είναι μια στατική
μέθοδος. Το όνομά του για τον επικυρωτή JavaScript δημιουργείται από τη
συνένωση του ονόματος της κλάσης χωρίς κάθετους \
, the underscore
_
, και του ονόματος της μεθόδου. Για παράδειγμα, γράψτε το
App\MyValidators::validateDivisibility
ως AppMyValidators_validateDivisibility
και
προσθέστε το στο αντικείμενο Nette.validators
:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
Γεγονός onValidate
Μετά την υποβολή της φόρμας, η επικύρωση πραγματοποιείται με τον
έλεγχο των επιμέρους κανόνων που έχουν προστεθεί από το addRule()
και στη συνέχεια με την κλήση του συμβάντος onValidate
. Ο χειριστής του
μπορεί να χρησιμοποιηθεί για πρόσθετη επικύρωση, συνήθως για την
επαλήθευση του σωστού συνδυασμού τιμών σε πολλαπλά στοιχεία της
φόρμας.
Εάν εντοπιστεί σφάλμα, αυτό μεταβιβάζεται στη φόρμα χρησιμοποιώντας
τη μέθοδο addError()
. Αυτή μπορεί να κληθεί είτε σε ένα συγκεκριμένο
στοιχείο είτε απευθείας στη φόρμα.
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('This combination is not possible.');
}
}
Σφάλματα επεξεργασίας
Σε πολλές περιπτώσεις, ανακαλύπτουμε ένα σφάλμα όταν
επεξεργαζόμαστε μια έγκυρη φόρμα, π.χ. όταν γράφουμε μια νέα εγγραφή
στη βάση δεδομένων και συναντάμε ένα διπλότυπο κλειδί. Σε αυτή την
περίπτωση, περνάμε το σφάλμα πίσω στη φόρμα χρησιμοποιώντας τη μέθοδο
addError()
. Αυτή μπορεί να κληθεί είτε σε ένα συγκεκριμένο στοιχείο
είτε απευθείας στη φόρμα:
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.');
}
}
Εάν είναι δυνατόν, συνιστούμε να προσθέσετε το σφάλμα απευθείας στο στοιχείο της φόρμας, καθώς θα εμφανίζεται δίπλα του όταν χρησιμοποιείτε τον προεπιλεγμένο renderer.
$form['date']->addError('Sorry, this date is already taken.');
Μπορείτε να καλέσετε επανειλημμένα το addError()
για να περάσετε
πολλαπλά μηνύματα σφάλματος σε μια φόρμα ή ένα στοιχείο. Τα λαμβάνετε
με το getErrors()
.
Σημειώστε ότι το $form->getErrors()
επιστρέφει μια σύνοψη όλων των
μηνυμάτων σφάλματος, ακόμη και εκείνων που έχουν περάσει απευθείας σε
μεμονωμένα στοιχεία, όχι μόνο απευθείας στη φόρμα. Τα μηνύματα
σφαλμάτων που περνούν μόνο στη φόρμα ανακτώνται μέσω του
$form->getOwnErrors()
.
Τροποποίηση τιμών εισόδου
Χρησιμοποιώντας τη μέθοδο addFilter()
, μπορούμε να τροποποιήσουμε
την τιμή που εισάγει ο χρήστης. Σε αυτό το παράδειγμα, θα ανεχτούμε και
θα αφαιρέσουμε τα κενά στον ταχυδρομικό κώδικα:
$form->addText('zip', 'Postcode:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // αφαίρεση των κενών από τον ταχυδρομικό κώδικα
})
->addRule($form::Pattern, 'The postal code is not five digits', '\d{5}');
Το φίλτρο περιλαμβάνεται μεταξύ των κανόνων επικύρωσης και των
συνθηκών και επομένως εξαρτάται από τη σειρά των μεθόδων, δηλαδή το
φίλτρο και ο κανόνας καλούνται με την ίδια σειρά που είναι η σειρά των
μεθόδων addFilter()
και addRule()
.
Επικύρωση JavaScript
Η γλώσσα των κανόνων επικύρωσης και των συνθηκών είναι ισχυρή. Παρόλο
που όλες οι κατασκευές λειτουργούν τόσο στην πλευρά του διακομιστή όσο
και στην πλευρά του πελάτη, στη JavaScript. Οι κανόνες μεταφέρονται σε
χαρακτηριστικά HTML data-nette-rules
ως JSON. Η ίδια η επικύρωση χειρίζεται
από ένα άλλο σενάριο, το οποίο αγκιστρώνει όλα τα συμβάντα της φόρμας
submit
, επαναλαμβάνει όλες τις εισόδους και εκτελεί τις
αντίστοιχες επικυρώσεις.
Αυτό το σενάριο είναι το netteForms.js
, το οποίο είναι διαθέσιμο από
διάφορες πιθανές πηγές:
Μπορείτε να ενσωματώσετε το σενάριο απευθείας στη σελίδα HTML από το CDN:
<script src="https://unpkg.com/nette-forms@3"></script>
ή να το αντιγράψετε τοπικά στο δημόσιο φάκελο του έργου (π.χ. από το
vendor/nette/forms/src/assets/netteForms.min.js
):
<script src="/path/to/netteForms.min.js"></script>
Ή εγκαταστήστε μέσω του npm:
npm install nette-forms
Και στη συνέχεια φορτώστε και εκτελέστε:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Εναλλακτικά, μπορείτε να το φορτώσετε απευθείας από το φάκελο
vendor
:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
Δυναμική JavaScript
Θέλετε να εμφανίσετε τα πεδία διεύθυνσης μόνο αν ο χρήστης επιλέξει
να στείλει τα αγαθά ταχυδρομικώς; Κανένα πρόβλημα. Το κλειδί είναι ένα
ζεύγος μεθόδων addCondition()
& toggle()
:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Αυτός ο κώδικας λέει ότι όταν ικανοποιείται η συνθήκη, δηλαδή όταν το
πλαίσιο ελέγχου είναι επιλεγμένο, το στοιχείο HTML #address-container
θα
είναι ορατό. Και το αντίστροφο. Έτσι, τοποθετούμε τα στοιχεία της
φόρμας με τη διεύθυνση του παραλήπτη σε ένα δοχείο με αυτό το ID, και
όταν πατηθεί το πλαίσιο ελέγχου, αυτά αποκρύπτονται ή εμφανίζονται.
Αυτό το χειρίζεται το σενάριο netteForms.js
.
Οποιοσδήποτε επιλογέας μπορεί να περάσει ως όρισμα στη μέθοδο
toggle()
. Για ιστορικούς λόγους, μια αλφαριθμητική συμβολοσειρά
χωρίς άλλους ειδικούς χαρακτήρες αντιμετωπίζεται ως αναγνωριστικό
στοιχείου, το ίδιο όπως αν προηγούνταν το #
character. The second optional
parameter allows us to reverse the behavior, i.e. if we used toggle('#address-container', false)
, το
στοιχείο θα εμφανιζόταν μόνο αν το πλαίσιο ελέγχου ήταν
απενεργοποιημένο.
Η προεπιλεγμένη εφαρμογή JavaScript αλλάζει την ιδιότητα hidden
για
τα στοιχεία. Ωστόσο, μπορούμε εύκολα να αλλάξουμε τη συμπεριφορά, για
παράδειγμα προσθέτοντας ένα animation. Απλά υπερκαλύψτε τη μέθοδο
Nette.toggle
στη JavaScript με μια προσαρμοσμένη λύση:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
Απενεργοποίηση της επικύρωσης
Σε ορισμένες περιπτώσεις, πρέπει να απενεργοποιήσετε την επικύρωση.
Εάν ένα κουμπί υποβολής δεν πρέπει να εκτελεί επικύρωση μετά την
υποβολή (για παράδειγμα το κουμπί Ακύρωση ή Προεπισκόπηση),
μπορείτε να απενεργοποιήσετε την επικύρωση καλώντας το
$submit->setValidationScope([])
. Μπορείτε επίσης να επικυρώσετε τη φόρμα
μερικώς καθορίζοντας στοιχεία προς επικύρωση.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Επικυρώνει ολόκληρη τη φόρμα
$form->addSubmit('send2')
->setValidationScope([]); // Δεν επικυρώνει τίποτα
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Επικυρώνει μόνο το πεδίο 'όνομα'
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Επικυρώνει μόνο το πεδίο 'age'.
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Επικυρώνει το δοχείο 'details'.
Το συμβάν onValidate στη φόρμα καλείται πάντα και δεν
επηρεάζεται από το setValidationScope
. Το συμβάν onValidate
στο δοχείο
καλείται μόνο όταν αυτό το δοχείο καθορίζεται για μερική επικύρωση.