Formulario para crear y editar un registro
¿Cómo implementar correctamente la adición y edición de un registro en Nette, utilizando el mismo formulario para ambos?
En muchos casos, los formularios para añadir y editar un registro son los mismos, diferenciándose quizás sólo en la etiqueta del botón. Mostraremos ejemplos de Presenters simples donde usaremos el formulario primero para añadir un registro, luego para editarlo, y finalmente combinaremos ambas soluciones.
Añadir un registro
Ejemplo de un Presenter que sirve para añadir un registro. Dejaremos el trabajo real con la base de datos a la clase
Facade
, cuyo código no es esencial para la demostración.
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;
// ... añadimos los campos del formulario ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // añadir registro a la base de datos
$this->flashMessage('Añadido correctamente');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Editar un registro
Ahora mostraremos cómo sería un Presenter para editar un 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 // verificar la existencia del registro
|| !$this->facade->isEditAllowed(/*...*/) // comprobar permisos
) {
$this->error(); // error 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// verificar que la acción es 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... añadimos los campos del formulario ...
$form->setDefaults($this->record); // establecer valores por defecto
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // actualizar el registro
$this->flashMessage('Actualizado correctamente');
$this->redirect('...');
}
}
En el método action, que se ejecuta al principio del ciclo de vida del Presenter, verificamos la existencia del registro y los permisos del usuario para editarlo.
Guardamos el registro en la propiedad $record
, para tenerlo disponible en el método
createComponentRecordForm()
para establecer los valores por defecto, y en recordFormSucceeded()
para el
ID. Una solución alternativa sería establecer los valores por defecto directamente en actionEdit()
y obtener el
valor del ID, que forma parte de la URL, usando getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// verificar existencia y comprobar permisos
) {
$this->error();
}
// establecer valores por defecto del formulario
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Sin embargo, y esto debería ser el punto más importante de todo el código, debemos asegurarnos al crear el formulario
de que la acción es realmente edit
. ¡Porque de lo contrario, la verificación en el método
actionEdit()
no se realizaría en absoluto!
El mismo formulario para añadir y editar
Y ahora combinaremos ambos Presenters en uno. Podríamos distinguir en el método createComponentRecordForm()
de
qué acción se trata y configurar el formulario en consecuencia, o podemos dejarlo directamente en los métodos action y
deshacernos de la condición:
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 // verificar la existencia del registro
|| !$this->facade->isEditAllowed(/*...*/) // comprobar permisos
) {
$this->error(); // error 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // establecer valores por defecto
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// verificamos que la acción es 'add' o 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... añadimos los campos del formulario ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // añadir registro a la base de datos
$this->flashMessage('Añadido correctamente');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // actualizar el registro
$this->flashMessage('Actualizado correctamente');
$this->redirect('...');
}
}