Form per creare e modificare un record
Come realizzare correttamente in Nette l'aggiunta e la modifica di un record usando per entrambe lo stesso form?
In molti casi i form per aggiungere e per modificare un record sono identici e si distinguono al massimo per l'etichetta del pulsante. Mostreremo esempi di presenter semplici in cui useremo il form prima per aggiungere un record, poi per modificarlo e infine uniremo le due soluzioni.
Aggiungere un record
Esempio di presenter per aggiungere un record. Lasceremo il lavoro vero e proprio sul database alla classe Facade,
il cui codice non è essenziale per questo esempio.
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;
// ... aggiunta dei campi del form ...
$form->onSuccess[] = $this->recordFormSucceeded(...);
return $form;
}
private function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // aggiunta del record al database
$this->flashMessage('Aggiunto con successo');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Modificare un record
Vediamo ora come apparirebbe un presenter per modificare un record:
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 dell'esistenza del record
|| !$this->facade->isEditAllowed(/*...*/) // controllo dei permessi
) {
$this->error(); // errore 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// verifica che l'azione sia 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... aggiunta dei campi del form ...
$form->setDefaults($this->record); // impostazione dei valori predefiniti
$form->onSuccess[] = $this->recordFormSucceeded(...);
return $form;
}
private function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // aggiornamento del record
$this->flashMessage('Aggiornato con successo');
$this->redirect('...');
}
}
Nel metodo action, che viene invocato all'inizio del ciclo di vita del presenter, verifichiamo l'esistenza del record e il permesso dell'utente di modificarlo.
Salviamo il record nella proprietà $record, così è disponibile nel metodo
createComponentRecordForm() per impostare i valori predefiniti e in recordFormSucceeded() per accedere
all'ID. Una soluzione alternativa è impostare i valori predefiniti direttamente in actionEdit() e ottenere il
valore dell'ID (parte dell'URL) con getParameter('id'):
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// verifica dell'esistenza e controllo dei permessi
) {
$this->error();
}
// impostazione dei valori predefiniti del form
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
Però, e questa dovrebbe essere la cosa più importante di tutto il codice, quando creiamo il form dobbiamo assicurarci
che l'azione sia davvero edit. Altrimenti la verifica nel metodo actionEdit() non avverrebbe
affatto!
Lo stesso form per aggiungere e modificare
Uniamo ora i due presenter in uno solo. Potremmo distinguere l'azione nel metodo createComponentRecordForm() e
configurare il form di conseguenza, oppure possiamo delegarlo direttamente ai metodi action ed eliminare il controllo
condizionale:
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 dell'esistenza del record
|| !$this->facade->isEditAllowed(/*...*/) // controllo dei permessi
) {
$this->error(); // errore 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // impostazione dei valori predefiniti
$form->onSuccess[] = $this->editingFormSucceeded(...);
}
protected function createComponentRecordForm(): Form
{
// verifica che l'azione sia 'add' oppure 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... aggiunta dei campi del form ...
return $form;
}
private function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // aggiunta del record al database
$this->flashMessage('Aggiunto con successo');
$this->redirect('...');
}
private function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // aggiornamento del record
$this->flashMessage('Aggiornato con successo');
$this->redirect('...');
}
}