Nyomtatvány rekord létrehozásához és szerkesztéséhez

Hogyan lehet megfelelően megvalósítani egy rekord hozzáadását és szerkesztését a Nette-ben, ugyanazt az űrlapot használva mindkettőhöz?

Sok esetben a rekord hozzáadására és szerkesztésére szolgáló űrlapok azonosak, csak a gomb címkéje különbözik. Példákat mutatunk egyszerű bemutatókra, ahol az űrlapot először egy rekord felvételére, majd szerkesztésére használjuk, végül pedig a két megoldást kombináljuk.

Rekord hozzáadása

Egy példa egy rekord hozzáadására használt prezenterre. A tényleges adatbázis-munkát a Facade osztályra hagyjuk, amelynek kódja a példa szempontjából nem releváns.

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;

		// ... űrlapmezők hozzáadása ...

		$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
	{
		// ...
	}
}

Felvétel szerkesztése

Most nézzük meg, hogyan nézne ki egy rekord szerkesztésére használt prezenter:

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 // ellenőrizze a nyilvántartás meglétét
			|| !$this->facade->isEditAllowed(/*...*/) // engedélyek ellenőrzése
		) {
			$this->error(); // 404 hiba
		}

		$this->record = $record;
	}

	protected function createComponentRecordForm(): Form
	{
		// ellenőrizze, hogy a művelet 'szerkesztés'
		if ($this->getAction() !== 'edit') {
			$this->error();
		}

		$form = new Form;

		// ... űrlapmezők hozzáadása ...

		$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, amelyet a prezenter életciklusának kezdetén hívunk meg, ellenőrizzük a rekord létezését és a felhasználó engedélyét a szerkesztésre.

A rekordot a $record tulajdonságban tároljuk, hogy a createComponentRecordForm() metódusban az alapértelmezések beállításához, valamint a recordFormSucceeded() azonosítóhoz rendelkezésre álljon. Egy alternatív megoldás az lenne, ha az alapértelmezett értékeket közvetlenül a actionEdit() -ban állítanánk be, és az ID értékét, amely az URL része, a getParameter('id') segítségével kérnénk le:

	public function actionEdit(int $id): void
	{
		$record = $this->facade->get($id);
		if (
			// ellenőrzi a létezést és a jogosultságokat
		) {
			$this->error();
		}

		// alapértelmezett űrlapértékek 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 lesz a legfontosabb tanulság az egész kódból, meg kell győződnünk arról, hogy a művelet valóban edit, amikor létrehozzuk az űrlapot. Mert különben a actionEdit() metódusban az érvényesítés egyáltalán nem történne meg!

Ugyanaz az űrlap a hozzáadáshoz és a szerkesztéshez

És most egyesítjük a két előadót egybe. Vagy megkülönböztetjük, hogy melyik műveletről van szó a createComponentRecordForm() módszerben, és ennek megfelelően konfiguráljuk az űrlapot, vagy közvetlenül az action-módszerekre bízzuk, és megszabadulunk 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 // ellenőrizze a nyilvántartás meglétét
			|| !$this->facade->isEditAllowed(/*...*/) // engedélyek 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őrizze, hogy a művelet "hozzáadás" vagy "szerkesztés".
		if (!in_array($this->getAction(), ['add', 'edit'])) {
			$this->error();
		}

		$form = new Form;

		// ... űrlapmezők hozzáadása ...

		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('...');
	}
}