Modulo per la creazione e la modifica di un record
Come implementare correttamente l'aggiunta e la modifica di un record in Nette, utilizzando lo stesso modulo per entrambi?
In molti casi, i moduli per l'aggiunta e la modifica di un record sono identici e si differenziano solo per l'etichetta del pulsante. Mostreremo esempi di semplici presentazioni in cui utilizziamo il modulo prima per aggiungere un record, poi per modificarlo e infine combiniamo le due soluzioni.
Aggiunta di un record
Un esempio di presentatore usato per aggiungere un record. Lasceremo il lavoro effettivo sul database alla classe
Facade
, il cui codice non è rilevante per l'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;
// ... aggiungere campi al modulo ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // aggiunge il record al database
$this->flashMessage('Aggiunto con successo');
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
Modifica di un record
Vediamo ora come appare un presentatore utilizzato 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 // verificare l'esistenza del record
|| !$this->facade->isEditAllowed(/*...*/) // verificare le autorizzazioni
) {
$this->error(); // errore 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// verificare che l'azione sia 'modifica'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... aggiungere campi del modulo ...
$form->setDefaults($this->record); // impostare i valori predefiniti
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // aggiorna il record
$this->flashMessage('Aggiornamento riuscito');
$this->redirect('...');
}
}
Nel metodo action, che viene invocato proprio all'inizio del ciclo di vita del presentatore, si verifica l'esistenza del record e l'autorizzazione dell'utente a modificarlo.
Memorizziamo il record nella proprietà $record
, in modo che sia disponibile nel metodo
createComponentRecordForm()
per l'impostazione dei valori predefiniti e recordFormSucceeded()
per l'ID.
Una soluzione alternativa sarebbe quella di impostare i valori predefiniti direttamente in actionEdit()
e il valore
dell'ID, che fa parte dell'URL, viene recuperato con getParameter('id')
:
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// verificare l'esistenza e controllare i permessi
) {
$this->error();
}
// impostare i valori predefiniti dei moduli
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
Tuttavia, e questo dovrebbe essere il risultato più importante di tutto il codice, dobbiamo assicurarci che l'azione
sia effettivamente edit
quando creiamo il form. Perché altrimenti la validazione nel metodo
actionEdit()
non avverrebbe affatto!
Stesso modulo per aggiungere e modificare
Ora combineremo entrambi i presentatori in uno solo. Si può distinguere quale azione è coinvolta nel metodo
createComponentRecordForm()
e configurare il modulo di conseguenza, oppure si può lasciare la scelta direttamente ai
metodi di azione e sbarazzarsi della condizione:
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 // verificare l'esistenza del record
|| !$this->facade->isEditAllowed(/*...*/) // verificare le autorizzazioni
) {
$this->error(); // errore 404
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // impostare le impostazioni predefinite
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// verificare che l'azione sia "aggiungere" o "modificare".
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... aggiungere i campi del modulo ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // aggiunge un record al database
$this->flashMessage('Aggiunto con successo');
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // aggiornamento del record
$this->flashMessage('Aggiornamento riuscito');
$this->redirect('...');
}
}