Obrazec za ustvarjanje in urejanje zapisa
Kako v Nette pravilno implementirati dodajanje in urejanje zapisa, pri čemer za oboje uporabimo isti obrazec?
V mnogih primerih so obrazci za dodajanje in urejanje zapisa enaki, razlikujejo se morda le po napisu na gumbu. Prikazali bomo primere preprostih presenterjev, kjer bomo obrazec najprej uporabili za dodajanje zapisa, nato za urejanje in na koncu obe rešitvi združili.
Dodajanje zapisa
Primer presenterja, ki služi za dodajanje zapisa. Samo delo s podatkovno bazo bomo prepustili razredu Facade
,
katerega koda za prikaz ni bistvena.
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;
// ... dodamo polja obrazca ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // dodajanje zapisa v podatkovno bazo
$this->flashMessage('Uspešno dodano');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Urejanje zapisa
Zdaj si poglejmo, kako bi izgledal presenter, ki služi za urejanje zapisa:
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 // preverjanje obstoja zapisa
|| !$this->facade->isEditAllowed(/*...*/) // preverjanje dovoljenj
) {
$this->error(); // napaka 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// preverimo, da je akcija 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... dodamo polja obrazca ...
$form->setDefaults($this->record); // nastavitev privzetih vrednosti
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // posodobitev zapisa
$this->flashMessage('Uspešno posodobljeno');
$this->redirect('...');
}
}
V metodi action, ki se zažene takoj na začetku življenjskega cikla presenterja, preverimo obstoj zapisa in dovoljenje uporabnika za urejanje.
Zapis shranimo v lastnost $record
, da ga imamo na voljo v metodi createComponentRecordForm()
za
nastavitev privzetih vrednosti in v recordFormSucceeded()
zaradi ID-ja. Alternativna rešitev bi bila nastavitev
privzetih vrednosti neposredno v actionEdit()
in pridobitev vrednosti ID, ki je del URL-ja, s pomočjo
getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// preverjanje obstoja in preverjanje dovoljenj
) {
$this->error();
}
// nastavitev privzetih vrednosti obrazca
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Vendar pa, in to bi moralo biti najpomembnejše spoznanje celotne kode, se moramo pri ustvarjanju obrazca prepričati,
da je akcija resnično edit
. Ker sicer preverjanje v metodi actionEdit()
sploh ne bi potekalo!
Isti obrazec za dodajanje in urejanje
In zdaj oba presenterja združimo v enega. Ali bi lahko v metodi createComponentRecordForm()
razlikovali, za
katero akcijo gre, in glede na to konfigurirali obrazec, ali pa to prepustimo neposredno action-metodam in se znebimo pogoja:
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 // preverjanje obstoja zapisa
|| !$this->facade->isEditAllowed(/*...*/) // preverjanje dovoljenj
) {
$this->error(); // napaka 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // nastavitev privzetih vrednosti
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// preverimo, da je akcija 'add' ali 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... dodamo polja obrazca ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // dodajanje zapisa v podatkovno bazo
$this->flashMessage('Uspešno dodano');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // posodobitev zapisa
$this->flashMessage('Uspešno posodobljeno');
$this->redirect('...');
}
}