Bağımsız Kullanılan Formlar

Nette Forms, web formlarının oluşturulmasını ve işlenmesini önemli ölçüde kolaylaştırır. Bu bölümde göstereceğimiz gibi, bunları uygulamalarınızda çerçevenin geri kalanı olmadan tamamen kendi başlarına kullanabilirsiniz.

Ancak, Nette Application ve presenters kullanıyorsanız, sizin için bir kılavuz var: presenters'daki formlar.

İlk Form

Basit bir kayıt formu yazmaya çalışacağız. Kodu şu şekilde görünecektir (tam kod):

use Nette\Forms\Form;

$form = new Form;
$form->addText('name', 'Name:');
$form->addPassword('password', 'Password:');
$form->addSubmit('send', 'Sign up');

Ve onu işleyelim:

$form->render();

ve sonuç aşağıdaki gibi görünmelidir:

Form, Nette\Forms\Form sınıfının bir nesnesidir ( Nette\Application\UI\Form sınıfı sunumlarda kullanılır). İçine isim, şifre ve gönder butonu kontrollerini ekledik.

Şimdi formu yeniden canlandıracağız. $form->isSuccess() adresine sorarak formun gönderilip gönderilmediğini ve geçerli bir şekilde doldurulup doldurulmadığını öğreneceğiz. Eğer öyleyse, verileri dökeceğiz. Formun tanımından sonra ekleyeceğiz:

if ($form->isSuccess()) {
	echo 'Form doğru şekilde dolduruldu ve gönderildi';
	$data = $form->getValues();
	// $data->name isim içeriyor
	// $data->password parola içerir
	var_dump($data);
}

getValues() yöntemi, gönderilen verileri bir ArrayHash nesnesi biçiminde döndürür. Bunu nasıl değiştireceğimizi daha sonra göstereceğiz. $data değişkeni, kullanıcı tarafından girilen verilerle birlikte name ve password anahtarlarını içerir.

Genellikle verileri, örneğin veritabanına ekleme gibi daha ileri işlemler için doğrudan göndeririz. Ancak, işleme sırasında bir hata oluşabilir, örneğin kullanıcı adı zaten alınmıştır. Bu durumda, addError() adresini kullanarak hatayı forma geri iletiriz ve bir hata mesajıyla birlikte yeniden çizilmesine izin veririz:

$form->addError('Sorry, username is already in use.');

Formu işledikten sonra bir sonraki sayfaya yönlendireceğiz. Bu, formun yenile, geri düğmesine tıklanarak veya tarayıcı geçmişi taşınarak istenmeden yeniden gönderilmesini önler.

Varsayılan olarak, form POST yöntemi kullanılarak aynı sayfaya gönderilir. Her ikisi de değiştirilebilir:

$form->setAction('/submit.php');
$form->setMethod('GET');

Ve hepsi bu kadar :-) İşlevsel ve mükemmel şekilde güvence altına alınmış bir formumuz var.

Daha fazla form denetimi eklemeyi deneyin.

Kontrollere Erişim

Form ve tek tek kontrolleri bileşen olarak adlandırılır. Bunlar, kökü form olan bir bileşen ağacı oluşturur. Tek tek kontrollere aşağıdaki şekilde erişebilirsiniz:

$input = $form->getComponent('name');
// alternatif sözdizimi: $input = $form['name'];

$button = $form->getComponent('send');
// alternatif sözdizimi: $button = $form['send'];

Kontroller unset kullanılarak kaldırılır:

unset($form['name']);

Doğrulama Kuralları

Burada geçerli kelimesi kullanıldı, ancak formun henüz doğrulama kuralları yok. Hadi düzeltelim.

Ad zorunlu olacaktır, bu nedenle onu, argümanı kullanıcı doldurmazsa görüntülenecek hata mesajının metni olan setRequired() yöntemiyle işaretleyeceğiz. Herhangi bir argüman verilmezse, varsayılan hata mesajı kullanılır.

$form->addText('name', 'Name:')
	->setRequired('Please enter a name.');

İsim doldurulmadan formu göndermeye çalıştığınızda bir hata mesajının görüntülendiğini ve siz doldurana kadar tarayıcı veya sunucunun formu reddettiğini göreceksiniz.

Aynı zamanda, örneğin girişe sadece boşluk yazarak sistemi aldatamazsınız. Mümkün değil. Nette sol ve sağ boşlukları otomatik olarak keser. Bunu deneyin. Bu, her tek satırlık girişte her zaman yapmanız gereken bir şeydir, ancak genellikle unutulur. Nette bunu otomatik olarak yapar. (Formları kandırmayı deneyebilir ve isim olarak çok satırlı bir dize gönderebilirsiniz. Burada bile Nette aldanmayacak ve satır sonları boşluk olarak değişecektir).

Form her zaman sunucu tarafında doğrulanır, ancak JavaScript doğrulaması da oluşturulur, bu da hızlıdır ve kullanıcı formu sunucuya göndermek zorunda kalmadan hatayı hemen öğrenir. Bu işlem netteForms.js betiği tarafından gerçekleştirilir. Bunu sayfaya ekleyin:

<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>

Formun bulunduğu sayfanın kaynak koduna bakarsanız, Nette'in gerekli alanları required CSS sınıfına sahip öğelere eklediğini fark edebilirsiniz. Aşağıdaki stili şablona eklemeyi deneyin, “Ad” etiketi kırmızı olacaktır. Kullanıcılar için gerekli alanları zarif bir şekilde işaretliyoruz:

<style>
.required label { color: maroon }
</style>

Ek doğrulama kuralları addRule() yöntemi ile eklenecektir. İlk parametre kuraldır, ikincisi yine hata mesajının metnidir ve isteğe bağlı doğrulama kuralı argümanı takip edebilir. Bu ne anlama geliyor?

Form, bir sayı olması (addInteger()) ve belirli sınırlar içinde olması ($form::Range) koşuluyla başka bir isteğe bağlı girdi yaş alacaktır. Ve burada addRule()'un üçüncü argümanı olan aralığın kendisini kullanacağız:

$form->addInteger('age', 'Age:')
	->addRule($form::Range, 'You must be older 18 years and be under 120.', [18, 120]);

Kullanıcı alanı doldurmazsa, alan isteğe bağlı olduğu için doğrulama kuralları doğrulanmayacaktır.

Açıkçası küçük bir yeniden düzenleme için yer mevcut. Hata mesajında ve üçüncü parametrede, sayılar çift olarak listelenmiştir ve bu ideal değildir. Çok dilli bir form oluşturuyor olsaydık ve sayıları içeren mesajın birden fazla dile çevrilmesi gerekseydi, değerleri değiştirmek daha zor olurdu. Bu nedenle, %d ikame karakterleri kullanılabilir:

	->addRule($form::Range, 'You must be older %d years and be under %d.', [18, 120]);

Parola* alanına geri dönelim, bunu gerekli yapalım ve yine mesajdaki yedek karakterleri kullanarak minimum parola uzunluğunu ($form::MinLength) doğrulayalım:

$form->addPassword('password', 'Password:')
	->setRequired('Pick a password')
	->addRule($form::MinLength, 'Your password has to be at least %d long', 8);

Kontrol için kullanıcının şifreyi tekrar girdiği forma passwordVerify şeklinde bir alan ekleyeceğiz. Doğrulama kurallarını kullanarak, her iki şifrenin de aynı olup olmadığını kontrol ediyoruz ($form::Equal). Ve bir argüman olarak köşeli parantez kullanarak ilk şifreye bir referans veriyoruz:

$form->addPassword('passwordVerify', 'Password again:')
	->setRequired('Fill your password again to check for typo')
	->addRule($form::Equal, 'Password mismatch', $form['password'])
	->setOmitted();

setOmitted() adresini kullanarak, değerini gerçekten önemsemediğimiz ve yalnızca doğrulama için var olan bir öğeyi işaretledik. Değeri $data adresine aktarılmaz.

PHP ve JavaScript'te doğrulama ile tamamen işlevsel bir formumuz var. Nette'nin doğrulama yetenekleri çok daha geniştir, koşullar oluşturabilir, bunlara göre bir sayfanın bölümlerini görüntüleyebilir ve gizleyebilirsiniz, vb. Her şeyi form doğrul ama bölümünde bulabilirsiniz.

Varsayılan Değerler

Form denetimleri için genellikle varsayılan değerler ayarlarız:

$form->addEmail('email', 'Email')
	->setDefaultValue($lastUsedEmail);

Genellikle tüm kontroller için varsayılan değerleri aynı anda ayarlamak yararlıdır. Örneğin, form kayıtları düzenlemek için kullanıldığında. Kaydı veritabanından okuruz ve varsayılan değerler olarak ayarlarız:

//$row = ['name' => 'John', 'age' => '33', /* ... */];
$form->setDefaults($row);

Kontrolleri tanımladıktan sonra setDefaults() adresini çağırın.

Formun Oluşturulması

Varsayılan olarak, form bir tablo olarak işlenir. Bireysel kontroller temel web erişilebilirlik yönergelerini takip eder. Tüm etiketler şu şekilde oluşturulur <label> elemanlarıdır ve girişleriyle ilişkilidir, etikete tıklamak imleci girişe taşır.

Her öğe için herhangi bir HTML niteliği ayarlayabiliriz. Örneğin, bir yer tutucu ekleyin:

$form->addInteger('age', 'Age:')
	->setHtmlAttribute('placeholder', 'Please fill in the age');

Bir formu oluşturmanın gerçekten pek çok yolu vardır, bu yüzden bu bölüm oluşturma konusuna ayrılmıştır.

Sınıflarla Eşleme

Form verilerinin işlenmesine geri dönelim. getValues() yöntemi gönderilen verileri bir ArrayHash nesnesi olarak döndürür. Bu stdClass gibi genel bir sınıf olduğundan, onunla çalışırken editörlerdeki özellikler için kod tamamlama veya statik kod analizi gibi bazı kolaylıklardan yoksun kalacağız. Bu, her form için, özellikleri ayrı kontrolleri temsil eden özel bir sınıfa sahip olarak çözülebilir. Örneğin:

class RegistrationFormData
{
	public string $name;
	public int $age;
	public string $password;
}

PHP 8.0'dan itibaren, bir kurucu kullanan bu zarif gösterimi kullanabilirsiniz:

class RegistrationFormData
{
	public function __construct(
		public string $name,
		public int $age,
		public string $password,
	) {
	}
}

Nette'e verileri bize bu sınıfın nesneleri olarak döndürmesini nasıl söyleyebiliriz? Düşündüğünüzden daha kolay. Tek yapmanız gereken parametre olarak hidrate edilecek sınıf adını veya nesneyi belirtmek:

$data = $form->getValues(RegistrationFormData::class);
$name = $data->name;

Parametre olarak bir 'array' adresi de belirtilebilir ve ardından veriler bir dizi olarak döndürülür.

Formlar konteynerlerden oluşan çok seviyeli bir yapıdan oluşuyorsa, her biri için ayrı bir sınıf oluşturun:

$form = new Form;
$person = $form->addContainer('person');
$person->addText('firstName');
/* ... */

class PersonFormData
{
	public string $firstName;
	public string $lastName;
}

class RegistrationFormData
{
	public PersonFormData $person;
	public int $age;
	public string $password;
}

Eşleme daha sonra $person özellik türünden konteyneri PersonFormData sınıfına eşlemesi gerektiğini bilir. Özellik bir kapsayıcı dizisi içerecekse, array türünü sağlayın ve doğrudan kapsayıcıyla eşlenecek sınıfı iletin:

$person->setMappedType(PersonFormData::class);

Tarayıcı sayfasına yazdıracak olan Nette\Forms\Blueprint::dataClass($form) yöntemini kullanarak bir formun veri sınıfı için bir öneri oluşturabilirsiniz. Daha sonra kodu seçmek ve projenize kopyalamak için tıklamanız yeterlidir.

Çoklu Gönder Düğmeleri

Formda birden fazla düğme varsa, genellikle hangisine basıldığını ayırt etmemiz gerekir. Düğmenin isSubmittedBy() yöntemi bize bu bilgiyi döndürür:

$form->addSubmit('save', 'Kaydet');
$form->addSubmit('delete', 'Sil');

if ($form->isSuccess()) {
	if ($form['save']->isSubmittedBy()) {
		// ...
	}

	if ($form['delete']->isSubmittedBy()) {
		// ...
	}
}

Verilerin geçerliliğini doğrulamak için $form->isSuccess() adresini atlamayın.

Bir form Enter tuşu ile gönderildiğinde, ilk düğme ile gönderilmiş gibi işlem görür.

Güvenlik Açığı Koruması

Nette Framework güvenli olmak için büyük çaba sarf eder ve formlar en yaygın kullanıcı girdisi olduğundan, Nette formları aşılmaz kadar iyidir.

Formları Siteler Arası Komut Dosyası Yazma (XSS) ve Siteler Arası İstek Sahteciliği (CSRF) gibi iyi bilinen saldırı açıklarına karşı korumanın yanı sıra, artık düşünmek zorunda olmadığınız birçok küçük güvenlik görevini de yerine getirir.

Örneğin, girdilerden tüm kontrol karakterlerini filtreler ve UTF-8 kodlamasının geçerliliğini kontrol eder, böylece formdan gelen veriler her zaman temiz olur. Seçim kutuları ve radyo listeleri için, seçilen öğelerin gerçekten sunulanlardan olduğunu ve herhangi bir sahtecilik olmadığını doğrular. Tek satırlı metin girişi için, bir saldırganın oraya gönderebileceği satır sonu karakterlerini kaldırdığından daha önce bahsetmiştik. Çok satırlı girdiler için satır sonu karakterlerini normalleştirir. Ve böyle devam eder.

Nette, çoğu programcının varlığından bile haberdar olmadığı güvenlik açıklarını sizin için düzeltir.

Bahsedilen CSRF saldırısı, bir saldırganın kurbanı, kurbanın tarayıcısında kurbanın o anda oturum açtığı sunucuya sessizce bir istek yürüten bir sayfayı ziyaret etmesi için kandırması ve sunucunun, isteğin kurban tarafından isteğe bağlı olarak yapıldığına inanmasıdır. Bu nedenle Nette, formun başka bir etki alanından POST yoluyla gönderilmesini engeller. Herhangi bir nedenle korumayı kapatmak ve formun başka bir etki alanından gönderilmesine izin vermek istiyorsanız, şunu kullanın:

$form->allowCrossOrigin(); // DİKKAT! Korumayı kapatır!

Bu koruma _nss adında bir SameSite çerezi kullanır. Bu nedenle, çerezin gönderilebilmesi için ilk çıktıyı flushing yapmadan önce bir form oluşturun.

SameSite çerez koruması %100 güvenilir olmayabilir, bu nedenle token korumasını açmak iyi bir fikirdir:

$form->addProtection();

Bu korumayı uygulamanızın hassas verileri değiştiren idari bölümündeki formlara uygulamanız şiddetle tavsiye edilir. Çerçeve, bir oturumda saklanan kimlik doğrulama belirtecini oluşturarak ve doğrulayarak CSRF saldırısına karşı koruma sağlar (argüman, belirtecin süresi dolmuşsa gösterilen hata mesajıdır). Bu nedenle formu görüntülemeden önce bir oturumun başlatılmış olması gerekir. Web sitesinin yönetim bölümünde, kullanıcının oturum açması nedeniyle oturum genellikle zaten başlatılmıştır. Aksi takdirde, oturumu Nette\Http\Session::start() yöntemi ile başlatın.

Böylece, Nette'deki formlara hızlı bir giriş yapmış olduk. Daha fazla ilham almak için dağıtımdaki örnekler dizinine bakmayı deneyin.

versiyon: 4.0