Επικύρωση Φορμών
Υποχρεωτικά Στοιχεία
Επισημαίνουμε τα υποχρεωτικά στοιχεία με τη μέθοδο setRequired()
. Το
όρισμά της είναι το κείμενο του μηνύματος σφάλματος
που θα εμφανιστεί εάν ο χρήστης δεν συμπληρώσει το στοιχείο. Εάν δεν
παρέχουμε όρισμα, θα χρησιμοποιηθεί το προεπιλεγμένο μήνυμα
σφάλματος.
$form->addText('name', 'Όνομα:')
->setRequired('Παρακαλώ εισάγετε το όνομά σας.');
Κανόνες
Προσθέτουμε κανόνες επικύρωσης στα στοιχεία χρησιμοποιώντας τη
μέθοδο addRule()
. Η πρώτη παράμετρος είναι ο κανόνας, η δεύτερη είναι
το κείμενο του μηνύματος σφάλματος και η τρίτη είναι
το όρισμα του κανόνα επικύρωσης.
$form->addPassword('password', 'Κωδικός πρόσβασης:')
->addRule($form::MinLength, 'Ο κωδικός πρόσβασης πρέπει να έχει μήκος τουλάχιστον %d χαρακτήρων.', 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 |
έγκυρη διεύθυνση 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
μετατρέπουν αμέσως την τιμή σε ακέραιο ή δεκαδικό, αντίστοιχα.
Επιπλέον, ο κανόνας URL
δέχεται επίσης μια διεύθυνση χωρίς σχήμα
(π.χ. nette.org
) και προσθέτει το σχήμα (https://nette.org
). Η έκφραση
στο Pattern
και το PatternIcase
πρέπει να ισχύει για ολόκληρη την
τιμή, δηλαδή σαν να ήταν περικλεισμένη από τους χαρακτήρες ^
και
$
.
Αριθμός Στοιχείων
Για τα στοιχεία 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, AVIF | – |
Pattern |
το όνομα αρχείου ταιριάζει με την κανονική έκφραση | string |
PatternInsensitive |
όπως το Pattern , αλλά χωρίς διάκριση πεζών-κεφαλαίων |
string |
Τα MimeType
και Image
απαιτούν την επέκταση PHP fileinfo
. Το
αν ένα αρχείο ή μια εικόνα είναι του απαιτούμενου τύπου ανιχνεύεται με
βάση την υπογραφή του και δεν επαληθεύει την ακεραιότητα ολόκληρου
του αρχείου. Το αν μια εικόνα είναι κατεστραμμένη μπορεί να
προσδιοριστεί, για παράδειγμα, προσπαθώντας να την φορτώσετε.
Μηνύματα Σφάλματος
Όλοι οι προκαθορισμένοι κανόνες, εκτός από τα Pattern
και
PatternInsensitive
, έχουν ένα προεπιλεγμένο μήνυμα σφάλματος, οπότε
μπορεί να παραλειφθεί. Ωστόσο, καθορίζοντας και διατυπώνοντας όλα τα
μηνύματα κατά παραγγελία, θα κάνετε τη φόρμα πιο φιλική προς τον
χρήστη.
Μπορείτε να αλλάξετε τα προεπιλεγμένα μηνύματα στην διαμόρφωση, επεξεργαζόμενοι τα κείμενα
στον πίνακα Nette\Forms\Validator::$messages
, ή χρησιμοποιώντας έναν μεταφραστή.
Οι ακόλουθες συμβολοσειρές κράτησης θέσης μπορούν να χρησιμοποιηθούν στο κείμενο των μηνυμάτων σφάλματος:
%d |
αντικαθίσταται διαδοχικά από τα ορίσματα του κανόνα |
%n$d |
αντικαθίσταται από το n-οστό όρισμα του κανόνα |
%label |
αντικαθίσταται από την ετικέτα του στοιχείου (χωρίς την άνω και κάτω τελεία) |
%name |
αντικαθίσταται από το όνομα του στοιχείου (π.χ. name ) |
%value |
αντικαθίσταται από την τιμή που εισήγαγε ο χρήστης |
$form->addText('name', 'Όνομα:')
->setRequired('Παρακαλώ συμπληρώστε το %label');
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'τουλάχιστον %d και το πολύ %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'το πολύ %2$d και τουλάχιστον %1$d', [5, 10]);
Συνθήκες
Εκτός από τους κανόνες, μπορούν επίσης να προστεθούν συνθήκες.
Γράφονται παρόμοια με τους κανόνες, αλλά αντί για addRule()
,
χρησιμοποιούμε τη μέθοδο addCondition()
, και φυσικά, δεν παρέχουμε
κανένα μήνυμα σφάλματος (η συνθήκη απλώς ρωτά):
$form->addPassword('password', 'Κωδικός πρόσβασης:')
// εάν ο κωδικός πρόσβασης δεν είναι μεγαλύτερος από 8 χαρακτήρες
->addCondition($form::MaxLength, 8)
// τότε πρέπει να περιέχει ένα ψηφίο
->addRule($form::Pattern, 'Πρέπει να περιέχει ένα ψηφίο.', '.*[0-9].*');
Η συνθήκη μπορεί επίσης να συνδεθεί με ένα στοιχείο διαφορετικό από
το τρέχον χρησιμοποιώντας το addConditionOn()
. Ως πρώτη παράμετρο,
παρέχουμε μια αναφορά στο στοιχείο. Σε αυτό το παράδειγμα, το email θα
είναι υποχρεωτικό μόνο εάν το πλαίσιο ελέγχου είναι επιλεγμένο (η τιμή
του θα είναι true):
$form->addCheckbox('newsletters', 'στείλτε μου ενημερωτικά δελτία');
$form->addEmail('email', 'E-mail:')
// εάν το πλαίσιο ελέγχου είναι επιλεγμένο
->addConditionOn($form['newsletters'], $form::Equal, true)
// τότε απαιτήστε το email
->setRequired('Παρακαλώ εισάγετε τη διεύθυνση email σας.');
Μπορείτε να δημιουργήσετε σύνθετες δομές από συνθήκες
χρησιμοποιώντας τα elseCondition()
και endCondition()
:
$form->addText(/* ... */)
->addCondition(/* ... */) // εάν η πρώτη συνθήκη πληρούται
->addConditionOn(/* ... */) // και η δεύτερη συνθήκη σε άλλο στοιχείο
->addRule(/* ... */) // απαιτήστε αυτόν τον κανόνα
->elseCondition() // εάν η δεύτερη συνθήκη δεν πληρούται
->addRule(/* ... */) // απαιτήστε αυτούς τους κανόνες
->addRule(/* ... */)
->endCondition() // επιστρέφουμε στην πρώτη συνθήκη
->addRule(/* ... */);
Στο Nette, είναι πολύ εύκολο να αντιδράσετε στην εκπλήρωση ή μη
εκπλήρωση μιας συνθήκης επίσης στην πλευρά του JavaScript χρησιμοποιώντας
τη μέθοδο toggle()
, δείτε δυναμικό-javascript.
Αναφορά σε Άλλο Στοιχείο
Ένα άλλο στοιχείο φόρμας μπορεί επίσης να περάσει ως όρισμα σε έναν
κανόνα ή μια συνθήκη. Ο κανόνας θα χρησιμοποιήσει τότε την τιμή που
εισήγαγε αργότερα ο χρήστης στο πρόγραμμα περιήγησης. Με αυτόν τον
τρόπο, μπορείτε, για παράδειγμα, να επικυρώσετε δυναμικά ότι το
στοιχείο password
περιέχει την ίδια συμβολοσειρά με το στοιχείο
password_confirm
:
$form->addPassword('password', 'Κωδικός πρόσβασης');
$form->addPassword('password_confirm', 'Επιβεβαιώστε τον κωδικό πρόσβασης')
->addRule($form::Equal, 'Οι κωδικοί πρόσβασης δεν ταιριάζουν.', $form['password']);
Προσαρμοσμένοι Κανόνες και Συνθήκες
Μερικές φορές βρισκόμαστε σε μια κατάσταση όπου οι ενσωματωμένοι κανόνες επικύρωσης στο Nette δεν είναι αρκετοί και πρέπει να επικυρώσουμε τα δεδομένα του χρήστη με τον δικό μας τρόπο. Στο Nette, αυτό είναι πολύ εύκολο!
Μπορείτε να περάσετε οποιαδήποτε επανάκληση ως πρώτη παράμετρο στις
μεθόδους addRule()
ή addCondition()
. Η επανάκληση δέχεται το ίδιο το
στοιχείο ως πρώτη παράμετρο και επιστρέφει μια 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'],
'Η τιμή πρέπει να είναι πολλαπλάσιο του %d.',
8,
);
Προσαρμοσμένοι κανόνες επικύρωσης μπορούν επίσης να προστεθούν στο
JavaScript. Η προϋπόθεση είναι ότι ο κανόνας είναι μια στατική μέθοδος. Το
όνομά του για τον επικυρωτή JavaScript δημιουργείται συνδυάζοντας το όνομα
της κλάσης χωρίς ανάστροφες καθέτους \
, μια κάτω παύλα _
και το όνομα της μεθόδου. Για παράδειγμα, το
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('Αυτός ο συνδυασμός δεν είναι δυνατός.');
}
}
Σφάλματα κατά την Επεξεργασία
Σε πολλές περιπτώσεις, μαθαίνουμε για ένα σφάλμα μόνο όταν
επεξεργαζόμαστε μια έγκυρη φόρμα, για παράδειγμα, όταν γράφουμε ένα
νέο στοιχείο στη βάση δεδομένων και συναντάμε διπλότυπα κλειδιά. Σε
αυτή την περίπτωση, περνάμε ξανά το σφάλμα στη φόρμα χρησιμοποιώντας
τη μέθοδο 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('Μη έγκυρος κωδικός πρόσβασης.');
}
}
Εάν είναι δυνατόν, συνιστούμε να επισυνάψετε το σφάλμα απευθείας στο στοιχείο της φόρμας, καθώς θα εμφανιστεί δίπλα του όταν χρησιμοποιείτε τον προεπιλεγμένο renderer.
$form['date']->addError('Συγγνώμη, αλλά αυτή η ημερομηνία είναι ήδη κατειλημμένη.');
Μπορείτε να καλέσετε το addError()
επανειλημμένα για να περάσετε
πολλαπλά μηνύματα σφάλματος στη φόρμα ή στο στοιχείο. Μπορείτε να τα
λάβετε χρησιμοποιώντας το getErrors()
.
Προσοχή, το $form->getErrors()
επιστρέφει μια σύνοψη όλων των
μηνυμάτων σφάλματος, συμπεριλαμβανομένων εκείνων που παραδόθηκαν
απευθείας σε μεμονωμένα στοιχεία, όχι μόνο απευθείας στη φόρμα.
Μπορείτε να λάβετε τα μηνύματα σφάλματος που παραδόθηκαν μόνο στη
φόρμα μέσω του $form->getOwnErrors()
.
Τροποποίηση Εισόδου
Χρησιμοποιώντας τη μέθοδο addFilter()
, μπορούμε να τροποποιήσουμε
την τιμή που εισήγαγε ο χρήστης. Σε αυτό το παράδειγμα, θα ανεχτούμε και
θα αφαιρέσουμε κενά στον ταχυδρομικό κώδικα:
$form->addText('zip', 'Τ.Κ.:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // αφαιρούμε τα κενά από τον Τ.Κ.
})
->addRule($form::Pattern, 'Ο Τ.Κ. δεν είναι στη μορφή πέντε ψηφίων.', '\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
θα
είναι ορατό. Και αντίστροφα. Έτσι, τοποθετούμε τα στοιχεία της φόρμας
με τη διεύθυνση του παραλήπτη σε ένα container με αυτό το ID, και όταν κάνουμε
κλικ στο πλαίσιο ελέγχου, θα αποκρυφθούν ή θα εμφανιστούν. Αυτό
διασφαλίζεται από το σενάριο netteForms.js
.
Οποιοσδήποτε επιλογέας μπορεί να περάσει ως όρισμα στη μέθοδο
toggle()
. Για ιστορικούς λόγους, μια αλφαριθμητική συμβολοσειρά
χωρίς άλλους ειδικούς χαρακτήρες νοείται ως το ID του στοιχείου, δηλαδή
σαν να προηγείται ο χαρακτήρας #
. Η δεύτερη προαιρετική
παράμετρος επιτρέπει την αντιστροφή της συμπεριφοράς, δηλαδή αν
χρησιμοποιούσαμε toggle('#address-container', false)
, το στοιχείο θα
εμφανιζόταν μόνο εάν το πλαίσιο ελέγχου δεν ήταν επιλεγμένο.
Η προεπιλεγμένη υλοποίηση στο JavaScript αλλάζει την ιδιότητα hidden
των στοιχείων. Ωστόσο, μπορούμε εύκολα να αλλάξουμε τη συμπεριφορά, για
παράδειγμα, προσθέτοντας μια κίνηση. Απλά αντικαταστήστε τη μέθοδο
Nette.toggle
στο JavaScript με τη δική σας λύση:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// απόκρυψη ή εμφάνιση του 'el' βάσει της τιμής 'visible'
});
};
Απενεργοποίηση Επικύρωσης
Μερικές φορές μπορεί να είναι χρήσιμο να απενεργοποιήσετε την
επικύρωση. Εάν το πάτημα ενός κουμπιού υποβολής δεν πρέπει να εκτελεί
επικύρωση (κατάλληλο για κουμπιά Ακύρωση ή Προεπισκόπηση),
μπορούμε να την απενεργοποιήσουμε χρησιμοποιώντας τη μέθοδο
$submit->setValidationScope([])
. Εάν πρέπει να εκτελεί μόνο μερική επικύρωση,
μπορούμε να καθορίσουμε ποια πεδία ή containers φόρμας πρέπει να
επικυρωθούν.
$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']]); // Επικυρώνει μόνο το στοιχείο name
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Επικυρώνει μόνο το στοιχείο age
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Επικυρώνει το container details
Το setValidationScope
δεν επηρεάζει το συμβάν
onValidate στη φόρμα, το οποίο θα καλείται πάντα. Το συμβάν onValidate
σε
ένα container θα ενεργοποιείται μόνο εάν αυτό το container έχει επισημανθεί για
μερική επικύρωση.