Formulário para criar e editar um registro
Como implementar corretamente a adição e edição de um registro no Nette, usando o mesmo formulário para ambos?
Em muitos casos, os formulários para adicionar e editar um registro são os mesmos, diferindo talvez apenas no rótulo do botão. Mostraremos exemplos de presenters simples onde usaremos o formulário primeiro para adicionar um registro, depois para editar e, finalmente, combinaremos ambas as soluções.
Adicionar um registro
Exemplo de um presenter usado para adicionar um registro. Deixaremos o trabalho real com o banco de dados para a classe
Facade
, cujo código não é essencial para a demonstração.
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;
// ... adicionamos os campos do formulário ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // adiciona o registro ao banco de dados
$this->flashMessage('Adicionado com sucesso');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Editar um registro
Agora mostraremos como seria um presenter usado para editar um registro:
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 // verifica a existência do registro
|| !$this->facade->isEditAllowed(/*...*/) // verifica a permissão
) {
$this->error(); // erro 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// verificamos se a ação é 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... adicionamos os campos do formulário ...
$form->setDefaults($this->record); // define os valores padrão
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // atualiza o registro
$this->flashMessage('Atualizado com sucesso');
$this->redirect('...');
}
}
No método actionEdit
, que é executado logo no início do ciclo de vida do presenter, verificamos a
existência do registro e a permissão do usuário para editá-lo.
Armazenamos o registro na propriedade $record
para tê-lo disponível no método
createComponentRecordForm()
para definir os valores padrão e em recordFormSucceeded()
para o ID. Uma
solução alternativa seria definir os valores padrão diretamente em actionEdit()
e obter o valor do ID, que faz
parte da URL, usando getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// verifica a existência e a permissão
) {
$this->error();
}
// define os valores padrão do formulário
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
No entanto, e isso deve ser o ponto mais importante de todo o código, devemos garantir ao criar o formulário que a
ação seja realmente edit
. Caso contrário, a verificação no método actionEdit()
não ocorreria de
forma alguma!
O mesmo formulário para adicionar e editar
E agora combinamos ambos os presenters em um só. Poderíamos distinguir qual ação está sendo realizada no método
createComponentRecordForm()
e configurar o formulário de acordo, ou podemos deixar isso diretamente para os
métodos de ação e nos livrar da condição:
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 // verifica a existência do registro
|| !$this->facade->isEditAllowed(/*...*/) // verifica a permissão
) {
$this->error(); // erro 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // define os valores padrão
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// verificamos se a ação é 'add' ou 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... adicionamos os campos do formulário ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // adiciona o registro ao banco de dados
$this->flashMessage('Adicionado com sucesso');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // atualiza o registro
$this->flashMessage('Atualizado com sucesso');
$this->redirect('...');
}
}