Form Doğrulama
Zorunlu Öğeler
Öğeler setRequired() metoduyla zorunlu işaretlenir. Argümanı, kullanıcı öğeyi doldurmazsa
görüntülenecek hata mesajının metnidir. Argüman verilmezse varsayılan hata mesajı
kullanılır.
$form->addText('name', 'Ad:')
->setRequired('Lütfen adınızı girin.');
Kurallar
Öğelere doğrulama kurallarını addRule() metoduyla ekleriz. İlk parametre kural, ikincisi hata mesajı, üçüncüsü ise doğrulama kuralının argümanıdır.
$form->addPassword('password', 'Parola:')
->addRule($form::MinLength, 'Parola en az %d karakter uzunluğunda olmalıdır', 8);
Doğrulama kuralları yalnızca kullanıcı öğeyi doldurduysa denetlenir.
Nette, adları Nette\Forms\Form sınıfının sabitleri olan birkaç önceden tanımlı kuralla gelir. Bu
kuralları tüm öğelere uygulayabiliriz:
| sabit | açıklama | argüman türü |
|---|---|---|
Required |
zorunlu öğe, setRequired() için takma ad |
– |
Filled |
zorunlu öğe, setRequired() için takma ad |
– |
Blank |
öğe doldurulmamalı | – |
Equal |
değer parametreye eşit olmalı | mixed |
NotEqual |
değer parametreye eşit olmamalı | mixed |
IsIn |
değer dizideki öğelerden biri olmalı | array |
IsNotIn |
değer dizideki öğelerden hiçbiri olmamalı | array |
Valid |
öğe doğru doldurulmuş mu? (yalnızca addConditionOn() içinde) | – |
Metin girdileri
addText(), addPassword(), addTextArea(), addEmail(),
addInteger(), addFloat() öğelerinde aşağıdaki kurallardan bazıları da uygulanabilir:
MinLength |
en az metin uzunluğu | int |
MaxLength |
en fazla metin uzunluğu | int |
Length |
aralıkta uzunluk ya da tam uzunluk | [int, int] çifti ya da int |
Email |
geçerli e-posta adresi | – |
URL |
mutlak URL | – |
Pattern |
düzenli ifadeyle eşleşir | string |
PatternInsensitive |
Pattern gibi, ama büyük/küçük harfe duyarsız |
string |
Integer |
tam sayı değeri | – |
Numeric |
negatif olmayan tam sayı (yalnızca rakamlar) | – |
Float |
sayı | – |
Min |
sayısal öğenin en küçük değeri | int|float |
Max |
sayısal öğenin en büyük değeri | int|float |
Range |
aralıkta değer | [int|float, int|float] çifti |
Integer ve Float doğrulama kuralları, değeri sırasıyla tam sayıya ya da kayan noktalı sayıya
otomatik dönüştürür. Ayrıca URL kuralı şemasız bir adresi de (örneğin nette.org) kabul eder
ve şemayı tamamlar (https://nette.org). Pattern ve PatternInsensitive içindeki ifade,
değerin tamamı için geçerli olmalıdır; yani ^ ve $ karakterleriyle sarılmış gibi.
Öğe Sayısı
addMultiUpload(), addCheckboxList(), addMultiSelect() öğelerinde, seçilen öğelerin
ya da yüklenen dosyaların sayısını sınırlamak için şu kuralları da kullanabilirsiniz:
MinLength |
en az sayı | int |
MaxLength |
en fazla sayı | int |
Length |
aralıkta sayı ya da tam sayı | [int, int] çifti ya da int |
Dosya Yükleme
addUpload(), addMultiUpload() öğelerinde şu kurallar da kullanılabilir:
MaxFileSize |
bayt cinsinden en fazla dosya boyutu | int |
MimeType |
MIME türü, joker karakterlere izin verilir ('video/*') |
string|string[] |
Image |
JPEG, PNG, GIF, WebP, AVIF görseli | – |
Pattern |
dosya adı düzenli ifadeyle eşleşir | string |
PatternInsensitive |
Pattern gibi, ama büyük/küçük harfe duyarsız |
string |
MimeType ve Image, fileinfo PHP eklentisini gerektirir. Bir dosyanın ya da görselin
gereken türde olup olmadığı imzasına göre saptanır ve dosyanın tamamının bütünlüğü denetlenmez. Bir
görselin bozuk olup olmadığını örneğin onu yüklemeyi
deneyerek belirleyebilirsiniz.
Hata Mesajları
Pattern ve PatternInsensitive dışındaki tüm önceden tanımlı kuralların varsayılan bir hata
mesajı vardır, bu yüzden atlanabilirler. Ancak tüm özel mesajları ihtiyacınıza göre verip biçimlendirerek formu daha
kullanıcı dostu kılarsınız.
Varsayılan mesajları yapılandırmada,
Nette\Forms\Validator::$messages dizisindeki metinleri değiştirerek ya da bir çevirmen kullanarak değiştirebilirsiniz.
Hata mesajlarının metninde şu yer tutucu dizeleri kullanılabilir:
%d |
sırayla kural argümanlarıyla değiştirilir |
%n$d |
n'inci kural argümanıyla değiştirilir |
%label |
öğenin etiketiyle değiştirilir (iki nokta olmadan) |
%name |
öğenin adıyla değiştirilir (örneğin name) |
%value |
kullanıcının girdiği değerle değiştirilir |
$form->addText('name', 'Ad:')
->setRequired('Lütfen %label doldurun');
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'en az %d ve en fazla %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'en fazla %2$d ve en az %1$d', [5, 10]);
Koşullar
Kuralların yanı sıra koşullar da eklenebilir. Kurallara benzer biçimde yazılırlar, ama addRule() yerine
addCondition() metodunu kullanırız ve doğal olarak hata mesajı vermeyiz (koşul yalnızca sorar):
$form->addPassword('password', 'Parola:')
// parolanın uzunluğu 8'den büyük değilse
->addCondition($form::MaxLength, 8)
// o zaman bir rakam içermeli
->addRule($form::Pattern, 'Bir rakam içermelidir', '.*[0-9].*');
Koşul, addConditionOn() ile geçerli öğe dışındaki bir öğeye bağlanabilir. İlk parametre öğeye bir
referanstır. Bu örnekte e-posta yalnızca onay kutusu işaretliyse (yani değeri true ise) zorunlu olacak:
$form->addCheckbox('newsletters', 'Bana bülten gönderin');
$form->addEmail('email', 'E-posta:')
// onay kutusu işaretliyse
->addConditionOn($form['newsletters'], $form::Equal, true)
// o zaman e-postayı zorunlu kıl
->setRequired('E-posta adresinizi girin');
Koşullar, elseCondition() ve endCondition() ile karmaşık yapılara dönüştürülebilir:
$form->addText(/* ... */)
->addCondition(/* ... */) // ilk koşul sağlanırsa
->addConditionOn(/* ... */) // ve başka bir öğedeki ikinci koşul da sağlanırsa
->addRule(/* ... */) // bu kuralı zorunlu kıl
->elseCondition() // ikinci koşul sağlanmazsa
->addRule(/* ... */) // bu kuralları zorunlu kıl
->addRule(/* ... */)
->endCondition() // ilk koşula geri döneriz
->addRule(/* ... */);
addCondition() metodunun ilk argümanı boolean bir değer de olabilir. Bu, karar form kurulurken zaten belliyse
işe yarar; örneğin bir kuralı yalnızca belirli koşullarda uygulamak için:
$form->addText('nickname')
->addCondition($isRequired) // form kurulurken bilinen bir değer
->setRequired();
Nette'te, bir koşulun sağlanmasına ya da sağlanmamasına JavaScript tarafında tepki vermek toggle() metoduyla
çok kolaydır, bkz. Dinamik JavaScript.
Başka Bir Öğeye Referans
Bir kurala ya da koşula argüman olarak başka bir form öğesi de aktarabilirsiniz. Kural o zaman kullanıcının
tarayıcıda sonradan girdiği değeri kullanır. Bu, örneğin password öğesinin password_confirm
öğesiyle aynı dizeyi içerdiğini dinamik olarak doğrulamak için kullanılabilir:
$form->addPassword('password', 'Parola');
$form->addPassword('password_confirm', 'Parolayı doğrulayın')
->addRule($form::Equal, 'Parolalar eşleşmiyor', $form['password']);
Özel Kurallar ve Koşullar
Bazen Nette'in yerleşik doğrulama kurallarının yetmediği ve kullanıcı verisini kendi yolumuzla doğrulamamız gereken durumlarla karşılaşırız. Nette'te bu çok basittir!
addRule() ya da addCondition() metotlarına ilk parametre olarak herhangi bir callback
aktarabilirsiniz. Callback, ilk parametre olarak öğenin kendisini alır ve doğrulamanın başarılı olup olmadığını
gösteren boolean bir değer döndürür. addRule() ile kural eklerken ek argümanlar verilebilir; bunlar ikinci
parametre olarak aktarılır.
Böylece özel bir doğrulayıcı kümesi, statik metotlar içeren bir sınıf olarak yazılabilir:
class MyValidators
{
// değerin argümana bölünüp bölünmediğini sınar
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// diğer doğrulayıcılar
}
}
Kullanımı ise çok dolaysızdır:
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'Değer %d sayısının katı olmalıdır',
8,
);
Özel doğrulama kuralları JavaScript'e de eklenebilir. Koşul, kuralın statik bir metot olmasıdır. JavaScript
doğrulayıcısı için adı; sınıf adının ters eğik çizgiler \ olmadan, bir alt çizgi _ ve metot
adının birleştirilmesiyle oluşur. Örneğin App\MyValidators::validateDivisibility,
AppMyValidators_validateDivisibility olarak yazılır ve Nette.validators nesnesine eklenir:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
onValidate Olayı
Form gönderildikten sonra doğrulama yapılır, addRule() ile eklenen tek tek kurallar denetlenir ve ardından
onValidate olayı tetiklenir. İşleyicisi ek doğrulama
için kullanılabilir; tipik olarak birden çok form öğesindeki değerlerin doğru bileşimini doğrulamak için.
Bir hata saptanırsa, addError() metoduyla forma aktarılır. Bu metot ya belirli bir öğede ya da doğrudan
formda çağrılabilir.
protected function createComponentSignInForm(): Form
{
$form = new Form;
// ...
$form->onValidate[] = $this->validateSignInForm(...);
return $form;
}
private function validateSignInForm(Form $form, \stdClass $data): void
{
if ($data->foo > 1 && $data->bar > 5) {
$form->addError('Bu bileşim olanaklı değil.');
}
}
İşleme Hataları
Pek çok durumda bir hatayı ancak geçerli bir formu işlerken keşfederiz; örneğin veritabanına yeni bir kayıt yazarken
yinelenen bir anahtarla karşılaşınca. Böyle bir durumda hatayı yine addError() metoduyla forma geri
aktarırız. Bu metot ya belirli bir öğede ya da doğrudan formda çağrılabilir:
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('Geçersiz parola.');
}
}
Olanaklıysa hatayı doğrudan form öğesine eklemenizi öneririz; çünkü varsayılan renderer kullanıldığında onun yanında görüntülenir.
$form['date']->addError('Üzgünüz, bu tarih zaten alınmış.');
Bir forma ya da öğeye birden çok hata mesajı aktarmak için addError() metodunu defalarca çağırabilirsiniz.
Onları getErrors() ile alabilirsiniz.
$form->getErrors() metodunun, yalnızca doğrudan forma değil, tek tek öğelere aktarılanlar da dahil olmak
üzere tüm hata mesajlarının bir özetini döndürdüğüne dikkat edin. Yalnızca forma aktarılan hata mesajları
$form->getOwnErrors() ile alınabilir.
Girdi Değerlerini Değiştirme
addFilter() metoduyla, kullanıcının girdiği değeri değiştirebiliriz. Bu örnekte posta kodundaki
boşluklara göz yumup onları kaldıracağız:
$form->addText('zip', 'Posta kodu:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // posta kodundaki boşlukları kaldır
})
->addRule($form::Pattern, 'Posta kodu beş rakam değil', '\d{5}');
Filtre, doğrulama kuralları ve koşulları arasına katılır, dolayısıyla metotların sırası önemlidir; yani filtre ve
kural, addFilter() ile addRule() metotlarının sıralandığı düzende çağrılır.
JavaScript Doğrulaması
Koşulları ve kuralları ifade etme dili çok güçlüdür. Tüm yapılar hem sunucu tarafında hem de istemci tarafında
JavaScript'te çalışır. data-nette-rules HTML niteliklerinde JSON olarak aktarılırlar. Doğrulamanın kendisini,
formun submit olayını yakalayan, tek tek öğeleri dolaşan ve ilgili doğrulamayı yapan bir betik üstlenir.
Bu betik netteForms.js'tir ve birkaç olası kaynaktan edinilebilir:
Betiği bir CDN'den doğrudan HTML sayfasına gömebilirsiniz:
<script src="https://unpkg.com/nette-forms@3"></script>
Ya da onu projenizin genel klasörüne yerel olarak kopyalayabilirsiniz (örneğin
vendor/nette/forms/src/assets/netteForms.min.js dosyasından):
<script src="/path/to/netteForms.min.js"></script>
Ya da onu npm ile kurabilirsiniz:
npm install nette-forms
Ve sonra yükleyip çalıştırabilirsiniz:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Alternatif olarak onu doğrudan vendor klasöründen yükleyebilirsiniz:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
Forma novalidate niteliğini ekleyerek istemci tarafı doğrulamayı tümüyle kapatabilirsiniz.
netteForms.js betiği o zaman gönderimde formu doğrulamayı atlar, dolayısıyla doğrulama yalnızca sunucuda
yapılır:
$form->setHtmlAttribute('novalidate');
Dinamik JavaScript
Adres alanlarını yalnızca kullanıcı malların postayla gönderilmesini seçtiğinde göstermek mi istiyorsunuz? Sorun
değil. Anahtar, addCondition() ve toggle() metot çiftidir:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Bu kod, koşul sağlandığında (yani onay kutusu işaretlendiğinde) #address-container HTML elemanının
görünür olacağını, tersi durumda ise görünmeyeceğini belirtir. Yani alıcının adresini içeren form öğelerini bu
ID'ye sahip bir container'a koyarız ve onay kutusuna tıklandığında gizlenip görünürler. Bunu netteForms.js
betiği üstlenir.
toggle() metoduna argüman olarak herhangi bir seçici aktarılabilir. Tarihsel nedenlerle, harf, rakam ya da alt
çizgiyle başlayan ve yalnızca harf, rakam, alt çizgi, tire, nokta ve iki nokta içeren bir dize, sanki başında
# karakteri varmış gibi eleman ID'si sayılır. İsteğe bağlı ikinci parametre davranışı tersine çevirmeye
olanak tanır; örneğin toggle('#address-container', false) kullansaydık, eleman yalnızca onay kutusu işaretli
değilse görüntülenirdi.
Varsayılan JavaScript gerçekleştirimi, elemanların hidden özelliğini değiştirir. Ancak davranışı,
örneğin bir animasyon ekleyerek kolayca değiştirebiliriz. Yalnızca JavaScript'te Nette.toggle metodunu kendi
çözümünüzle geçersiz kılın:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// 'visible' değerine göre 'el' elemanını gizle ya da göster
});
};
Doğrulamayı Kapatma
Bazen doğrulamayı kapatmak yararlı olabilir. Bir gönder düğmesine basmak doğrulama yapmamalıysa (İptal ya da
Önizleme düğmeleri için uygundur), onu $submit->setValidationScope([]) metoduyla kapatırız. Yalnızca
kısmi doğrulama yapmalıysa, hangi alanların ya da form container'larının doğrulanacağını belirtebiliriz.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Formun tamamını doğrular
$form->addSubmit('send2')
->setValidationScope([]); // Hiçbir şeyi doğrulamaz
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Yalnızca 'name' öğesini doğrular
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Yalnızca 'age' öğesini doğrular
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // 'details' container'ını doğrular
setValidationScope, formdaki onValidate Olayı olayını etkilemez; o her
zaman çağrılır. Bir container'daki onValidate olayı yalnızca o container kısmi doğrulama için
işaretlenmişse tetiklenir.
Kısmi doğrulama, getValues() metodunun döndürdüğü değerleri de etkiler: sonuç yalnızca doğrulama
kapsamına giren öğelerin değerlerini içerir. Bu kapsamın dışındaki öğelerin değerleri atlanır.