Formulář pro vytvoření i editaci záznamu
Jak správně v Nette implementovat přidání a editaci záznamu, s tím, že pro obojí využijeme tentýž formulář?
V mnoha případech bývají formuláře pro přidání i editaci záznamu stejné, liší se třeba jen popiskou na tlačítku. Ukážeme příklady jednoduchých presenterů, kde formulář použijeme nejprve pro přidání záznamu, poté pro editaci a nakonec obě řešení spojíme.
Přidání záznamu
Příklad presenteru sloužícího k přidání záznamu. Samotnou práci s databází necháme na třídě
Facade
, jejíž kód není pro ukázku podstatný.
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;
// ... přidáme políčka formuláře ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // přidání záznamu do databáze
$this->flashMessage('Successfully added');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Editace záznamu
Nyní si ukážeme, jak by vypadal presenter sloužící k editaci záznamu:
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 // oveření existence záznamu
|| !$this->facade->isEditAllowed(/*...*/) // kontrola oprávnění
) {
$this->error(); // chyba 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// ověříme, že akce je 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... přidáme políčka formuláře ...
$form->setDefaults($this->record); // nastavení výchozích hodnot
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // aktualizace záznamu
$this->flashMessage('Successfully updated');
$this->redirect('...');
}
}
V metodě action, která se spouští hned na začátku životního cyklu presenteru, ověříme existenci záznamu a oprávnění uživatele jej editovat.
Záznam si uložíme do property $record
, abychom jej měli k dispozici v metodě
createComponentRecordForm()
kvůli nastavení výchozích hodnot, a recordFormSucceeded()
kvůli ID.
Alternativním řešením by bylo nastavit výchozí hodnoty přímo v actionEdit()
a hodnotu ID, která je
součástí URL, získat pomocí getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// oveření existence a kontrola oprávnění
) {
$this->error();
}
// nastavení výchozích hodnot formuláře
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Nicméně, a to by mělo být nejdůležitejším poznatkem celého kódu, musíme se při tvorbě formuláře ujistit,
že akce je skutečně edit
. Protože jinak by ověření v metodě actionEdit()
vůbec
neproběhlo!
Stejný formulář pro přidání i editaci
A nyní oba presentery spojíme do jednoho. Buď bychom mohli v metodě createComponentRecordForm()
rozlišit,
o kterou akci jde a podle toho formulář nakonfigurovat, nebo to můžeme nechat přímo na action-metodách a zbavit se
podmínky:
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 // oveření existence záznamu
|| !$this->facade->isEditAllowed(/*...*/) // kontrola oprávnění
) {
$this->error(); // chyba 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // nastavení výchozích hodnot
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// ověříme, že akce je 'add' nebo 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... přidáme políčka formuláře ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // přidání záznamu do databáze
$this->flashMessage('Successfully added');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // aktualizace záznamu
$this->flashMessage('Successfully updated');
$this->redirect('...');
}
}