Nette Documentation Preview

syntax
Formular pentru crearea și modificarea unei înregistrări
********************************************************

.[perex]
Cum se implementează în mod corespunzător adăugarea și editarea unei înregistrări în Nette, utilizând același formular pentru ambele?

În multe cazuri, formularele de adăugare și de editare a unei înregistrări sunt identice, diferind doar prin eticheta de pe buton. Vom prezenta exemple de prezentări simple în care folosim formularul mai întâi pentru a adăuga o înregistrare, apoi pentru a o edita și, în final, vom combina cele două soluții.


Adăugarea unei înregistrări .[#toc-adding-a-record]
---------------------------------------------------

Un exemplu de prezentator utilizat pentru a adăuga o înregistrare. Vom lăsa activitatea efectivă a bazei de date pe seama clasei `Facade`, al cărei cod nu este relevant pentru acest exemplu.


```php
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;

		// ... adăugați câmpuri de formular ...

		$form->onSuccess[] = [$this, 'recordFormSucceeded'];
		return $form;
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$this->facade->add($data); // adăugarea unei înregistrări în baza de date
		$this->flashMessage('Successfully added');
		$this->redirect('...');
	}

	public function renderAdd(): void
	{
		// ...
	}
}
```


Editarea unei înregistrări .[#toc-editing-a-record]
---------------------------------------------------

Acum să vedem cum ar arăta un prezentator utilizat pentru a edita o înregistrare:


```php
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 // să verifice existența înregistrării
			|| !$this->facade->isEditAllowed(/*...*/) // verificarea permisiunilor
		) {
			$this->error(); // Eroare 404
		}

		$this->record = $record;
	}

	protected function createComponentRecordForm(): Form
	{
		// verificați dacă acțiunea este "edit" (editare)
		if ($this->getAction() !== 'edit') {
			$this->error();
		}

		$form = new Form;

		// ... adăugați câmpuri de formular ...

		$form->setDefaults($this->record); // setați valorile implicite
		$form->onSuccess[] = [$this, 'recordFormSucceeded'];
		return $form;
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$this->facade->update($this->record->id, $data); // actualizează înregistrarea
		$this->flashMessage('Successfully updated');
		$this->redirect('...');
	}
}
```

În metoda *action*, care este invocată chiar la începutul [ciclului de viață al prezentatorului |application:presenters#Life Cycle of Presenter], se verifică existența înregistrării și permisiunea utilizatorului de a o edita.

Stocăm înregistrarea în proprietatea `$record`, astfel încât să fie disponibilă în metoda `createComponentRecordForm()` pentru setarea valorilor implicite și `recordFormSucceeded()` pentru ID. O soluție alternativă ar fi să setați valorile implicite direct în `actionEdit()`, iar valoarea ID, care face parte din URL, este recuperată cu ajutorul `getParameter('id')`:


```php
	public function actionEdit(int $id): void
	{
		$record = $this->facade->get($id);
		if (
			// verificarea existenței și verificarea permisiunilor
		) {
			$this->error();
		}

		// stabilirea valorilor implicite ale formularelor
		$this->getComponent('recordForm')
			->setDefaults($record);
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$id = (int) $this->getParameter('id');
		$this->facade->update($id, $data);
		// ...
	}
}
```

Cu toate acestea, și aceasta ar trebui să fie **cea mai importantă concluzie din tot acest cod**, trebuie să ne asigurăm că acțiunea este într-adevăr `edit` atunci când creăm formularul. Pentru că, altfel, validarea din metoda `actionEdit()` nu ar avea loc deloc!


Același formular pentru adăugare și editare .[#toc-same-form-for-adding-and-editing]
------------------------------------------------------------------------------------

Și acum vom combina ambii prezentatori într-unul singur. Fie putem distinge ce acțiune este implicată în metoda `createComponentRecordForm()` și configura formularul în consecință, fie putem lăsa direct pe seama metodelor de acțiune și să scăpăm de condiție:


```php
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 // să verifice existența înregistrării
			|| !$this->facade->isEditAllowed(/*...*/) // verificarea permisiunilor
		) {
			$this->error(); // Eroare 404
		}

		$form = $this->getComponent('recordForm');
		$form->setDefaults($record); // setați valorile implicite
		$form->onSuccess[] = [$this, 'editingFormSucceeded'];
	}

	protected function createComponentRecordForm(): Form
	{
		// verifică dacă acțiunea este "add" sau "edit".
		if (!in_array($this->getAction(), ['add', 'edit'])) {
			$this->error();
		}

		$form = new Form;

		// ... adaugă câmpuri de formular ...

		return $form;
	}

	public function addingFormSucceeded(Form $form, array $data): void
	{
		$this->facade->add($data); // adăugarea unei înregistrări în baza de date
		$this->flashMessage('Successfully added');
		$this->redirect('...');
	}

	public function editingFormSucceeded(Form $form, array $data): void
	{
		$id = (int) $this->getParameter('id');
		$this->facade->update($id, $data); // actualizează înregistrarea
		$this->flashMessage('Successfully updated');
		$this->redirect('...');
	}
}
```

{{priority: -1}}
{{sitename: Best Practices}}

Formular pentru crearea și modificarea unei înregistrări

Cum se implementează în mod corespunzător adăugarea și editarea unei înregistrări în Nette, utilizând același formular pentru ambele?

În multe cazuri, formularele de adăugare și de editare a unei înregistrări sunt identice, diferind doar prin eticheta de pe buton. Vom prezenta exemple de prezentări simple în care folosim formularul mai întâi pentru a adăuga o înregistrare, apoi pentru a o edita și, în final, vom combina cele două soluții.

Adăugarea unei înregistrări

Un exemplu de prezentator utilizat pentru a adăuga o înregistrare. Vom lăsa activitatea efectivă a bazei de date pe seama clasei Facade, al cărei cod nu este relevant pentru acest exemplu.

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;

		// ... adăugați câmpuri de formular ...

		$form->onSuccess[] = [$this, 'recordFormSucceeded'];
		return $form;
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$this->facade->add($data); // adăugarea unei înregistrări în baza de date
		$this->flashMessage('Successfully added');
		$this->redirect('...');
	}

	public function renderAdd(): void
	{
		// ...
	}
}

Editarea unei înregistrări

Acum să vedem cum ar arăta un prezentator utilizat pentru a edita o înregistrare:

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 // să verifice existența înregistrării
			|| !$this->facade->isEditAllowed(/*...*/) // verificarea permisiunilor
		) {
			$this->error(); // Eroare 404
		}

		$this->record = $record;
	}

	protected function createComponentRecordForm(): Form
	{
		// verificați dacă acțiunea este "edit" (editare)
		if ($this->getAction() !== 'edit') {
			$this->error();
		}

		$form = new Form;

		// ... adăugați câmpuri de formular ...

		$form->setDefaults($this->record); // setați valorile implicite
		$form->onSuccess[] = [$this, 'recordFormSucceeded'];
		return $form;
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$this->facade->update($this->record->id, $data); // actualizează înregistrarea
		$this->flashMessage('Successfully updated');
		$this->redirect('...');
	}
}

În metoda action, care este invocată chiar la începutul ciclului de viață al prezentatorului, se verifică existența înregistrării și permisiunea utilizatorului de a o edita.

Stocăm înregistrarea în proprietatea $record, astfel încât să fie disponibilă în metoda createComponentRecordForm() pentru setarea valorilor implicite și recordFormSucceeded() pentru ID. O soluție alternativă ar fi să setați valorile implicite direct în actionEdit(), iar valoarea ID, care face parte din URL, este recuperată cu ajutorul getParameter('id'):

	public function actionEdit(int $id): void
	{
		$record = $this->facade->get($id);
		if (
			// verificarea existenței și verificarea permisiunilor
		) {
			$this->error();
		}

		// stabilirea valorilor implicite ale formularelor
		$this->getComponent('recordForm')
			->setDefaults($record);
	}

	public function recordFormSucceeded(Form $form, array $data): void
	{
		$id = (int) $this->getParameter('id');
		$this->facade->update($id, $data);
		// ...
	}
}

Cu toate acestea, și aceasta ar trebui să fie cea mai importantă concluzie din tot acest cod, trebuie să ne asigurăm că acțiunea este într-adevăr edit atunci când creăm formularul. Pentru că, altfel, validarea din metoda actionEdit() nu ar avea loc deloc!

Același formular pentru adăugare și editare

Și acum vom combina ambii prezentatori într-unul singur. Fie putem distinge ce acțiune este implicată în metoda createComponentRecordForm() și configura formularul în consecință, fie putem lăsa direct pe seama metodelor de acțiune și să scăpăm de condiție:

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 // să verifice existența înregistrării
			|| !$this->facade->isEditAllowed(/*...*/) // verificarea permisiunilor
		) {
			$this->error(); // Eroare 404
		}

		$form = $this->getComponent('recordForm');
		$form->setDefaults($record); // setați valorile implicite
		$form->onSuccess[] = [$this, 'editingFormSucceeded'];
	}

	protected function createComponentRecordForm(): Form
	{
		// verifică dacă acțiunea este "add" sau "edit".
		if (!in_array($this->getAction(), ['add', 'edit'])) {
			$this->error();
		}

		$form = new Form;

		// ... adaugă câmpuri de formular ...

		return $form;
	}

	public function addingFormSucceeded(Form $form, array $data): void
	{
		$this->facade->add($data); // adăugarea unei înregistrări în baza de date
		$this->flashMessage('Successfully added');
		$this->redirect('...');
	}

	public function editingFormSucceeded(Form $form, array $data): void
	{
		$id = (int) $this->getParameter('id');
		$this->facade->update($id, $data); // actualizează înregistrarea
		$this->flashMessage('Successfully updated');
		$this->redirect('...');
	}
}