Űrlap rekord létrehozásához és szerkesztéséhez
Hogyan implementáljuk helyesen a Nette-ben egy rekord hozzáadását és szerkesztését úgy, hogy mindkettőhöz ugyanazt az űrlapot használjuk?
Sok esetben a rekord hozzáadására és szerkesztésére szolgáló űrlapok ugyanazok, legfeljebb a gomb felirata különbözik. Egyszerű presenterek példáit mutatjuk be, ahol az űrlapot először rekord hozzáadására, majd szerkesztésére használjuk, végül pedig egyesítjük a két megoldást.
Rekord hozzáadása
Példa egy presenter-re, amely rekord hozzáadására szolgál. Magát az adatbázis-kezelést a Facade
osztályra
bízzuk, amelynek kódja a példa szempontjából nem lényeges.
use Nette\Application\UI\Form;
class RecordPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Facade $facade,
) {
}
protected function createComponentRecordForm(): Form
{
$form = new Form;
// ... hozzáadjuk az űrlap mezőit ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // rekord hozzáadása az adatbázishoz
$this->flashMessage('Sikeresen hozzáadva');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Rekord szerkesztése
Most megmutatjuk, hogyan nézne ki egy presenter, amely rekord szerkesztésére szolgál:
use Nette\Application\UI\Form;
class RecordPresenter extends Nette\Application\UI\Presenter
{
private $record;
public function __construct(
private Facade $facade,
) {
}
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
!$record // rekord létezésének ellenőrzése
|| !$this->facade->isEditAllowed(/*...*/) // jogosultság ellenőrzése
) {
$this->error(); // 404 hiba
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// ellenőrizzük, hogy az akció 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... hozzáadjuk az űrlap mezőit ...
$form->setDefaults($this->record); // alapértelmezett értékek beállítása
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // rekord frissítése
$this->flashMessage('Sikeresen frissítve');
$this->redirect('...');
}
}
Az action metódusban, amely rögtön a presenter életciklusának elején fut le, ellenőrizzük a rekord létezését és a felhasználó jogosultságát annak szerkesztésére.
A rekordot a $record
property-be mentjük, hogy elérhető legyen a createComponentRecordForm()
metódusban az alapértelmezett értékek beállításához, és a recordFormSucceeded()
metódusban az ID miatt.
Alternatív megoldásként beállíthatnánk az alapértelmezett értékeket közvetlenül az actionEdit()
metódusban, és az URL részét képező ID értékét a getParameter('id')
segítségével szerezhetnénk meg:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// létezés ellenőrzése és jogosultság ellenőrzése
) {
$this->error();
}
// űrlap alapértelmezett értékeinek beállítása
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Azonban, és ez kellene, hogy az egész kód legfontosabb tanulsága legyen, az űrlap létrehozásakor meg kell
győződnünk arról, hogy az akció valóban edit
. Mert különben az actionEdit()
metódusban lévő
ellenőrzés egyáltalán nem futna le!
Ugyanaz az űrlap hozzáadáshoz és szerkesztéshez
És most egyesítjük a két presentert egybe. Vagy megkülönböztethetnénk a createComponentRecordForm()
metódusban, hogy melyik akcióról van szó, és ennek megfelelően konfigurálhatnánk az űrlapot, vagy ezt közvetlenül az
action-metódusokra bízhatnánk, és megszabadulhatnánk a feltételtől:
class RecordPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Facade $facade,
) {
}
public function actionAdd(): void
{
$form = $this->getComponent('recordForm');
$form->onSuccess[] = [$this, 'addingFormSucceeded'];
}
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
!$record // rekord létezésének ellenőrzése
|| !$this->facade->isEditAllowed(/*...*/) // jogosultság ellenőrzése
) {
$this->error(); // 404 hiba
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // alapértelmezett értékek beállítása
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// ellenőrizzük, hogy az akció 'add' vagy 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... hozzáadjuk az űrlap mezőit ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // rekord hozzáadása az adatbázishoz
$this->flashMessage('Sikeresen hozzáadva');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // rekord frissítése
$this->flashMessage('Sikeresen frissítve');
$this->redirect('...');
}
}