Форма за създаване и редактиране на запис
Как правилно да се реализира добавяне и редактиране на запис в Nette, като се използва една и съща форма и за двете?
В много случаи формите за добавяне и редактиране на записи са еднакви, като се различават само по етикета на бутона. Ще покажем примери за прости презентери, където ще използваме формата първо за добавяне на запис, след това за редактиране и накрая ще комбинираме двете решения.
Добавяне на запис
Пример за презентер, използван за добавяне на запис. Ще оставим
действителната работа с базата данни на класа Facade
, чийто код не
е от съществено значение за примера.
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;
// ... добавяме полета към формата ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // добавяне на запис в базата данни
$this->flashMessage('Успешно добавено');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Редактиране на запис
Сега ще покажем как би изглеждал презентер, използван за редактиране на запис:
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 // проверка за съществуване на запис
|| !$this->facade->isEditAllowed(/*...*/) // проверка на правата
) {
$this->error(); // грешка 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// проверяваме дали действието е 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... добавяме полета към формата ...
$form->setDefaults($this->record); // задаване на стойности по подразбиране
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // актуализиране на запис
$this->flashMessage('Успешно актуализирано');
$this->redirect('...');
}
}
В метода action, който се стартира в самото начало на жизнения цикъл на презентера, проверяваме съществуването на записа и правата на потребителя да го редактира.
Запазваме записа в свойството $record
, за да го имаме на
разположение в метода createComponentRecordForm()
за задаване на стойности
по подразбиране и в recordFormSucceeded()
заради ID. Алтернативно решение
би било да зададем стойностите по подразбиране директно в
actionEdit()
и да получим стойността на ID, която е част от URL адреса,
като използваме getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// проверка за съществуване и проверка на правата
) {
$this->error();
}
// задаване на стойности по подразбиране на формата
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Въпреки това, и това трябва да бъде най-важният извод от целия код,
трябва да се уверим при създаването на формата, че действието наистина
е edit
. В противен случай проверката в метода actionEdit()
изобщо
няма да се извърши!
Същата форма за добавяне и редактиране
И сега комбинираме двата презентера в един. Можем или да разграничим
в метода createComponentRecordForm()
кое е действието и да конфигурираме
формата съответно, или можем да го оставим директно на action-методите и
да се отървем от условието:
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 // проверка за съществуване на запис
|| !$this->facade->isEditAllowed(/*...*/) // проверка на правата
) {
$this->error(); // грешка 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // задаване на стойности по подразбиране
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// проверяваме дали действието е 'add' или 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... добавяме полета към формата ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // добавяне на запис в базата данни
$this->flashMessage('Успешно добавено');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // актуализиране на запис
$this->flashMessage('Успешно актуализирано');
$this->redirect('...');
}
}