Önállóan használt űrlapok
A Nette Forms nagyságrendekkel megkönnyíti a webes űrlapok létrehozását és feldolgozását. Alkalmazásaiban teljesen önállóan is használhatja őket a keretrendszer többi része nélkül, amit ebben a fejezetben bemutatunk.
Ha azonban a Nette Applicationt és a presentereket használja, akkor a használat presenterekben útmutató Önnek szól.
Első űrlap
Próbáljunk meg írni egy egyszerű regisztrációs űrlapot. A kódja a következő lesz (teljes kód):
use Nette\Forms\Form;
$form = new Form;
$form->addText('name', 'Név:');
$form->addPassword('password', 'Jelszó:');
$form->addSubmit('send', 'Regisztráció');
Nagyon könnyen megjeleníthetjük:
$form->render();
és a böngészőben így jelenik meg:

Az űrlap a Nette\Forms\Form
osztály objektuma (a Nette\Application\UI\Form
osztályt a
presenterekben használják). Hozzáadtuk az úgynevezett név, jelszó elemeket és egy küldés gombot.
Most pedig keltsük életre az űrlapot. A $form->isSuccess()
lekérdezésével megtudjuk, hogy az űrlapot
elküldték-e és érvényesen töltötték-e ki. Ha igen, kiírjuk az adatokat. Az űrlapdefiníció után tehát
hozzáadjuk:
if ($form->isSuccess()) {
echo 'Az űrlap helyesen lett kitöltve és elküldve';
$data = $form->getValues();
// $data->name tartalmazza a nevet
// $data->password tartalmazza a jelszót
var_dump($data);
}
A getValues()
metódus az elküldött adatokat ArrayHash objektum formájában adja vissza. Hogy ezt hogyan lehet
megváltoztatni, azt később mutatjuk be. A $data
objektum tartalmazza
a name
és password
kulcsokat a felhasználó által megadott adatokkal.
Általában az adatokat azonnal további feldolgozásra küldjük, ami lehet például adatbázisba való beszúrás.
A feldolgozás során azonban hiba léphet fel, például a felhasználónév már foglalt. Ebben az esetben a hibát az
addError()
segítségével visszaküldjük az űrlapnak, és újra megjelenítjük, a hibaüzenettel együtt.
$form->addError('Elnézést, ezt a felhasználónevet már használja valaki.');
Az űrlap feldolgozása után átirányítunk a következő oldalra. Ez megakadályozza az űrlap nem kívánt újraküldését a frissítés, vissza gombbal vagy a böngésző előzményeiben való mozgással.
Az űrlap alapértelmezés szerint POST metódussal és ugyanarra az oldalra küldődik. Mindkettő megváltoztatható:
$form->setAction('/submit.php');
$form->setMethod('GET');
És ez tulajdonképpen minden :-) Van egy működő és tökéletesen biztonságos űrlapunk.
Próbáljon meg hozzáadni más űrlap elemeket is.
Elemekhez való hozzáférés
Az űrlapot és annak egyes elemeit komponenseknek nevezzük. Komponensfát alkotnak, ahol a gyökér maga az űrlap. Az űrlap egyes elemeihez a következő módon férhetünk hozzá:
$input = $form->getComponent('name');
// alternatív szintaxis: $input = $form['name'];
$button = $form->getComponent('send');
// alternatív szintaxis: $button = $form['send'];
Az elemeket az unset segítségével távolítjuk el:
unset($form['name']);
Validációs szabályok
Elhangzott az érvényes szó, de az űrlapnak még nincsenek validációs szabályai. Javítsuk ki ezt.
A név kötelező lesz, ezért a setRequired()
metódussal jelöljük meg, amelynek argumentuma a hibaüzenet
szövege, amely akkor jelenik meg, ha a felhasználó nem tölti ki a nevet. Ha nem adunk meg argumentumot, az alapértelmezett
hibaüzenet kerül felhasználásra.
$form->addText('name', 'Név:')
->setRequired('Kérjük, adja meg a nevét');
Próbálja meg elküldeni az űrlapot a név kitöltése nélkül, és látni fogja, hogy hibaüzenet jelenik meg, és a böngésző vagy a szerver addig elutasítja, amíg ki nem tölti a mezőt.
Ugyanakkor a rendszert nem lehet becsapni azzal, hogy például csak szóközöket ír a mezőbe. Nem. A Nette automatikusan eltávolítja a bal és jobb oldali szóközöket. Próbálja ki. Ezt minden egysoros beviteli mezővel meg kellene tenni, de gyakran elfelejtik. A Nette ezt automatikusan megteszi. (Megpróbálhatja becsapni az űrlapot, és névként többsoros stringet küldeni. A Nette itt sem hagyja magát becsapni, és a sortöréseket szóközökre cseréli.)
Az űrlap mindig a szerveroldalon validálódik, de JavaScript validáció is generálódik, amely villámgyorsan lefut, és a
felhasználó azonnal értesül a hibáról, anélkül, hogy az űrlapot el kellene küldenie a szerverre. Ezt a
netteForms.js
szkript végzi. Illessze be az oldalba:
<script src="https://unpkg.com/nette-forms@3"></script>
Ha megnézi az űrlapot tartalmazó oldal forráskódját, észreveheti, hogy a Nette a kötelező elemeket
required
CSS osztállyal rendelkező elemekbe helyezi. Próbálja meg hozzáadni a következő stíluslapot a
sablonhoz, és a „Név” címke piros lesz. Így elegánsan jelölhetjük meg a felhasználók számára a kötelező
elemeket:
<style>
.required label { color: maroon }
</style>
További validációs szabályokat az addRule()
metódussal adunk hozzá. Az első paraméter a szabály, a
második ismét a hibaüzenet szövege, és még következhet a validációs szabály argumentuma. Mit jelent ez?
Az űrlapot kibővítjük egy új, nem kötelező „kor” mezővel, amelynek egész számnak kell lennie
(addInteger()
), és ezen felül egy megengedett tartományban kell lennie ($form::Range
). És itt
pontosan az addRule()
metódus harmadik paraméterét használjuk, amellyel átadjuk a validátornak a kívánt
tartományt [tól, ig]
párként:
$form->addInteger('age', 'Életkor:')
->addRule($form::Range, 'Az életkornak 18 és 120 között kell lennie', [18, 120]);
Ha a felhasználó nem tölti ki a mezőt, a validációs szabályok nem kerülnek ellenőrzésre, mivel az elem nem kötelező.
Itt van lehetőség egy kis refaktorálásra. A hibaüzenetben és a harmadik paraméterben a számok duplikáltan
szerepelnek, ami nem ideális. Ha többnyelvű űrlapokat
hoznánk létre, és a számokat tartalmazó üzenet több nyelvre lenne lefordítva, megnehezítené az értékek esetleges
megváltoztatását. Emiatt lehetséges a %d
helyettesítő karakterek használata, és a Nette kiegészíti az
értékeket:
->addRule($form::Range, 'Az életkornak %d és %d év között kell lennie', [18, 120]);
Térjünk vissza a password
elemhez, amelyet szintén kötelezővé teszünk, és még ellenőrizzük a jelszó
minimális hosszát ($form::MinLength
), ismét a helyettesítő karakter használatával:
$form->addPassword('password', 'Jelszó:')
->setRequired('Válasszon jelszót')
->addRule($form::MinLength, 'A jelszónak legalább %d karakter hosszúnak kell lennie', 8);
Adunk hozzá az űrlaphoz még egy passwordVerify
mezőt, ahol a felhasználó még egyszer megadja a jelszót,
ellenőrzés céljából. A validációs szabályok segítségével ellenőrizzük, hogy a két jelszó megegyezik-e
($form::Equal
). És paraméterként hivatkozást adunk az első jelszóra a szögletes zárójelek segítségével:
$form->addPassword('passwordVerify', 'Jelszó ellenőrzéshez:')
->setRequired('Kérjük, adja meg a jelszót még egyszer ellenőrzés céljából')
->addRule($form::Equal, 'A jelszavak nem egyeznek', $form['password'])
->setOmitted();
A setOmitted()
segítségével megjelöltük azt az elemet, amelynek az értéke valójában nem számít, és
amely csak a validáció miatt létezik. Az érték nem kerül átadásra a $data
-ba.
Ezzel van egy teljesen működőképes űrlapunk validációval PHP-ban és JavaScriptben is. A Nette validációs képességei sokkal szélesebbek, lehet feltételeket létrehozni, azok alapján megjeleníteni és elrejteni az oldal részeit stb. Mindent megtudhat az űrlapok validációjáról szóló fejezetben.
Alapértelmezett értékek
Az űrlap elemeinek általában alapértelmezett értékeket állítunk be:
$form->addEmail('email', 'E-mail')
->setDefaultValue($lastUsedEmail);
Gyakran hasznos az összes elem alapértelmezett értékét egyszerre beállítani. Például, ha az űrlap rekordok szerkesztésére szolgál. Beolvassuk a rekordot az adatbázisból, és beállítjuk az alapértelmezett értékeket:
//$row = ['name' => 'John', 'age' => '33', /* ... */];
$form->setDefaults($row);
Hívja a setDefaults()
metódust az elemek definiálása után.
Űrlap megjelenítése
Alapértelmezés szerint az űrlap táblázatként jelenik meg. Az egyes elemek megfelelnek az alapvető hozzáférhetőségi
szabálynak – minden címke <label>
-ként van megírva, és a megfelelő űrlap elemhez van kapcsolva.
A címkére kattintva a kurzor automatikusan az űrlap mezőjébe kerül.
Minden elemhez beállíthatunk tetszőleges HTML attribútumokat. Például hozzáadhatunk egy placeholdert:
$form->addInteger('age', 'Életkor:')
->setHtmlAttribute('placeholder', 'Kérjük, töltse ki az életkort');
Az űrlap megjelenítésének módjai valóban nagyon sokfélék, ezért ennek külön fejezetet szentelünk a megjelenítésről.
Osztályokra való leképezés
Térjünk vissza az űrlapadatok feldolgozásához. A getValues()
metódus az elküldött adatokat
ArrayHash
objektumként adta vissza. Mivel ez egy generikus osztály, valami olyasmi, mint a stdClass
,
hiányozni fog belőle bizonyos kényelem a vele való munka során, mint például a propertyk súgása a szerkesztőkben vagy a
statikus kódelemzés. Ezt úgy lehetne megoldani, hogy minden űrlaphoz lenne egy konkrét osztályunk, amelynek propertyjei az
egyes elemeket reprezentálják. Pl.:
class RegistrationFormData
{
public string $name;
public ?int $age;
public string $password;
}
Alternatívaként használhatja a konstruktort:
class RegistrationFormData
{
public function __construct(
public string $name,
public int $age,
public string $password,
) {
}
}
Az adatosztály propertyjei lehetnek enumok is, és automatikusan leképezésre kerülnek.
Hogyan mondjuk meg a Nette-nek, hogy az adatokat ennek az osztálynak az objektumaiként adja vissza? Könnyebben, mint gondolná. Csak az osztály nevét vagy a hidratálandó objektumot kell paraméterként megadni:
$data = $form->getValues(RegistrationFormData::class);
$name = $data->name;
Paraméterként megadható az 'array'
is, és akkor az adatokat tömbként adja vissza.
Ha az űrlapok többszintű struktúrát alkotnak konténerekből, hozzon létre mindegyikhez külön osztályt:
$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;
}
A leképezés ezután a $person
property típusából tudja, hogy a konténert a PersonFormData
osztályra kell leképeznie. Ha a property konténerek tömbjét tartalmazná, adja meg az array
típust, és adja
át a leképezendő osztályt közvetlenül a konténernek:
$person->setMappedType(PersonFormData::class);
Az űrlap adatosztályának tervét legeneráltathatja a
Nette\Forms\Blueprint::dataClass($form)
metódussal, amely kiírja azt a böngésző oldalára. A kódot ezután
elég egy kattintással kijelölni és a projektbe másolni.
Több gomb
Ha az űrlapnak több mint egy gombja van, általában meg kell különböztetnünk, melyiket nyomták meg. Ezt az
információt a gomb isSubmittedBy()
metódusa adja vissza:
$form->addSubmit('save', 'Mentés');
$form->addSubmit('delete', 'Törlés');
if ($form->isSuccess()) {
if ($form['save']->isSubmittedBy()) {
// ...
}
if ($form['delete']->isSubmittedBy()) {
// ...
}
}
Ne hagyja ki a $form->isSuccess()
lekérdezést, ezzel ellenőrzi az adatok érvényességét.
Amikor az űrlapot az Enter gombbal küldik el, úgy veszi, mintha az első gombbal küldték volna el.
Védelem a sebezhetőségek ellen
A Nette Framework nagy hangsúlyt fektet a biztonságra, ezért gondosan ügyel az űrlapok megfelelő védelmére.
Amellett, hogy az űrlapokat megvédi a Cross Site Scripting (XSS) és a Cross-Site Request Forgery (CSRF) támadásoktól, számos apró biztonsági intézkedést tesz, amelyekre Önnek már nem kell gondolnia.
Például kiszűri az összes vezérlőkaraktert a bemenetekből, és ellenőrzi az UTF-8 kódolás érvényességét, így az űrlap adatai mindig tiszták lesznek. A select boxoknál és radio listáknál ellenőrzi, hogy a kiválasztott elemek valóban a felajánlottak közül valók-e, és nem történt-e hamisítás. Már említettük, hogy az egysoros szöveges beviteleknél eltávolítja a sorvégi karaktereket, amelyeket a támadó küldhetett volna. A többsoros beviteleknél pedig normalizálja a sorvégi karaktereket. És így tovább.
A Nette megoldja Ön helyett azokat a biztonsági kockázatokat, amelyekről sok programozó nem is tudja, hogy léteznek.
Az említett CSRF támadás lényege, hogy a támadó egy olyan oldalra csalja az áldozatot, amely észrevétlenül végrehajt egy kérést az áldozat böngészőjében ahhoz a szerverhez, amelyen az áldozat be van jelentkezve, és a szerver azt hiszi, hogy a kérést az áldozat saját akaratából hajtotta végre. Ezért a Nette megakadályozza a POST űrlapok küldését más domainről. Ha valamilyen okból ki akarja kapcsolni a védelmet, és engedélyezni szeretné az űrlap küldését más domainről, használja a következőt:
$form->allowCrossOrigin(); // FIGYELEM! Kikapcsolja a védelmet!
Ez a védelem a _nss
nevű SameSite cookie-t használja. Ezért hozza létre az űrlap objektumot még az első
kimenet elküldése előtt, hogy a cookie elküldhető legyen.
A SameSite cookie-val történő védelem nem feltétlenül 100%-ban megbízható, ezért célszerű bekapcsolni a token alapú védelmet is:
$form->addProtection();
Javasoljuk, hogy így védje azokat az űrlapokat a webhely adminisztrációs részében, amelyek érzékeny adatokat
módosítanak az alkalmazásban. A keretrendszer a CSRF támadás ellen egy engedélyezési token generálásával és
ellenőrzésével védekezik, amelyet a sessionben tárol. Ezért az űrlap megjelenítése előtt nyitott sessionre van
szükség. A webhely adminisztrációs részében általában már elindult a session a felhasználó bejelentkezése miatt.
Ellenkező esetben indítsa el a sessiont a Nette\Http\Session::start()
metódussal.
Nos, ezzel végeztünk a Nette űrlapjainak gyors bemutatásával. Próbáljon meg még belenézni a disztribúció examples könyvtárába, ahol további inspirációt találhat.