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 entrambe le operazioni?
In molti casi i moduli per l'aggiunta e la modifica di un record sono gli stessi, differendo magari solo per l'etichetta sul pulsante. Mostreremo esempi di semplici presenter in cui utilizzeremo il modulo prima per aggiungere un record, poi per modificarlo e infine combineremo entrambe le soluzioni.
Aggiunta di un record
Esempio di un presenter utilizzato per aggiungere un record. Lasceremo il lavoro effettivo con il database alla classe
Facade
, il cui codice non è essenziale 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;
// ... aggiungiamo i campi del modulo ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public 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
{
// ...
}
}
Modifica di un record
Ora mostreremo come apparirebbe un presenter 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 // verifica dell'esistenza del record
|| !$this->facade->isEditAllowed(/*...*/) // controllo dei permessi
) {
$this->error(); // errore 404
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// verifichiamo che l'azione sia 'edit'
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... aggiungiamo i campi del modulo ...
$form->setDefaults($this->record); // impostazione dei valori predefiniti
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public 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 eseguito all'inizio del ciclo di vita del presenter, verifichiamo l'esistenza del record e i permessi dell'utente per modificarlo.
Salviamo il record nella proprietà $record
in modo da averlo disponibile nel metodo
createComponentRecordForm()
per impostare i valori predefiniti e in recordFormSucceeded()
per l'ID. Una
soluzione alternativa sarebbe impostare i valori predefiniti direttamente in actionEdit()
e ottenere il valore
dell'ID, che fa parte dell'URL, utilizzando 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 modulo
$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 punto chiave più importante dell'intero codice, dobbiamo assicurarci durante la
creazione del modulo che l'azione sia effettivamente edit
. Altrimenti, la verifica nel metodo
actionEdit()
non verrebbe eseguita affatto!
Stesso modulo per l'aggiunta e la modifica
E ora uniamo entrambi i presenter in uno solo. Potremmo distinguere quale azione è in corso nel metodo
createComponentRecordForm()
e configurare il modulo di conseguenza, oppure possiamo lasciarlo direttamente ai metodi
action e liberarci 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 // 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
{
// verifichiamo che l'azione sia 'add' o 'edit'
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... aggiungiamo i campi del modulo ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // aggiunta del 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('Aggiornato con successo');
$this->redirect('...');
}
}