Nette Documentation Preview

syntax
Επαναχρησιμοποίηση φορμών σε πολλαπλά σημεία
********************************************

.[perex]
Στη Nette, έχετε αρκετές επιλογές για να επαναχρησιμοποιήσετε την ίδια φόρμα σε πολλά σημεία χωρίς να αντιγράψετε κώδικα. Σε αυτό το άρθρο, θα εξετάσουμε τις διάφορες λύσεις, συμπεριλαμβανομένων αυτών που πρέπει να αποφύγετε.


Εργοστάσιο φορμών .[#toc-form-factory]
======================================

Μια βασική προσέγγιση για τη χρήση του ίδιου συστατικού σε πολλά σημεία είναι η δημιουργία μιας μεθόδου ή κλάσης που παράγει το συστατικό και στη συνέχεια η κλήση αυτής της μεθόδου σε διαφορετικά σημεία της εφαρμογής. Μια τέτοια μέθοδος ή κλάση ονομάζεται *factory*. Μην συγχέετε με το πρότυπο σχεδίασης *factory method*, το οποίο περιγράφει έναν συγκεκριμένο τρόπο χρήσης των εργοστασίων και δεν σχετίζεται με αυτό το θέμα.

Για παράδειγμα, ας δημιουργήσουμε ένα εργοστάσιο που θα δημιουργήσει μια φόρμα επεξεργασίας:

```php
use Nette\Application\UI\Form;

class FormFactory
{
	public function createEditForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Τώρα μπορείτε να χρησιμοποιήσετε αυτό το εργοστάσιο σε διάφορα σημεία της εφαρμογής σας, για παράδειγμα σε παρουσιαστές ή στοιχεία. Και το κάνουμε αυτό [ζητώντας το ως εξάρτηση |dependency-injection:passing-dependencies]. Έτσι, πρώτα, θα γράψουμε την κλάση στο αρχείο ρυθμίσεων:

```neon
services:
	- FormFactory
```

Και στη συνέχεια τη χρησιμοποιούμε στον παρουσιαστή:


```php
class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->createEditForm();
		$form->onSuccess[] = function () {
			// επεξεργασία των δεδομένων που αποστέλλονται
		};
		return $form;
	}
}
```

Μπορείτε να επεκτείνετε το εργοστάσιο φορμών με πρόσθετες μεθόδους για να δημιουργήσετε άλλους τύπους φορμών ανάλογα με την εφαρμογή σας. Και, φυσικά, μπορείτε να προσθέσετε μια μέθοδο που δημιουργεί μια βασική φόρμα χωρίς στοιχεία, την οποία θα χρησιμοποιούν οι άλλες μέθοδοι:

```php
class FormFactory
{
	public function createForm(): Form
	{
		$form = new Form;
		return $form;
	}

	public function createEditForm(): Form
	{
		$form = $this->createForm();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Η μέθοδος `createForm()` δεν κάνει τίποτα χρήσιμο ακόμα, αλλά αυτό θα αλλάξει γρήγορα.


Εξαρτήσεις εργοστασίων .[#toc-factory-dependencies]
===================================================

Με τον καιρό, θα γίνει προφανές ότι χρειαζόμαστε τις φόρμες να είναι πολύγλωσσες. Αυτό σημαίνει ότι πρέπει να δημιουργήσουμε έναν [μεταφραστή |forms:rendering#Translating] για όλες τις φόρμες. Για να το κάνουμε αυτό, τροποποιούμε την κλάση `FormFactory` ώστε να δέχεται το αντικείμενο `Translator` ως εξάρτηση στον κατασκευαστή και να το περνάει στη φόρμα:

```php
use Nette\Localization\Translator;

class FormFactory
{
	public function __construct(
		private Translator $translator,
	) {
	}

	public function createForm(): Form
	{
		$form = new Form;
		$form->setTranslator($this->translator);
		return $form;
	}

	//...
}
```

Δεδομένου ότι η μέθοδος `createForm()` καλείται και από άλλες μεθόδους που δημιουργούν συγκεκριμένες φόρμες, χρειάζεται να ορίσουμε τον μεταφραστή μόνο σε αυτή τη μέθοδο. Και τελειώσαμε. Δεν χρειάζεται να αλλάξουμε τον κώδικα του παρουσιαστή ή του συστατικού, πράγμα που είναι υπέροχο.


Περισσότερες εργοστασιακές κλάσεις .[#toc-more-factory-classes]
===============================================================

Εναλλακτικά, μπορείτε να δημιουργήσετε πολλαπλές κλάσεις για κάθε φόρμα που θέλετε να χρησιμοποιήσετε στην εφαρμογή σας.
Αυτή η προσέγγιση μπορεί να αυξήσει την αναγνωσιμότητα του κώδικα και να διευκολύνει τη διαχείριση των φορμών. Αφήστε το αρχικό `FormFactory` για να δημιουργήσετε μόνο μια καθαρή φόρμα με βασικές ρυθμίσεις (για παράδειγμα, με υποστήριξη μετάφρασης) και δημιουργήστε ένα νέο εργοστάσιο `EditFormFactory` για τη φόρμα επεξεργασίας.

```php
class FormFactory
{
	public function __construct(
		private Translator $translator,
	) {
	}

	public function create(): Form
	{
		$form = new Form;
		$form->setTranslator($this->translator);
		return $form;
	}
}


// ✅ χρήση της σύνθεσης
class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		// εδώ προστίθενται πρόσθετα πεδία φόρμας
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Είναι πολύ σημαντικό ότι η σύνδεση μεταξύ των κλάσεων `FormFactory` και `EditFormFactory` υλοποιείται [με σύνθεση |nette:introduction-to-object-oriented-programming#composition] και όχι με [κληρονομικότητα αντικειμένων |https://doc.nette.org/en/introduction-to-object-oriented-programming#inheritance]:

```php
// ⛔ ΟΧΙ! Η ΚΛΗΡΟΝΟΜΙΆ ΔΕΝ ΑΝΉΚΕΙ ΕΔΏ
class EditFormFactory extends FormFactory
{
	public function create(): Form
	{
		$form = parent::create();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Η χρήση κληρονομικότητας σε αυτή την περίπτωση θα ήταν εντελώς αντιπαραγωγική. Θα αντιμετωπίζατε προβλήματα πολύ γρήγορα. Για παράδειγμα, αν θέλατε να προσθέσετε παραμέτρους στη μέθοδο `create()`, η PHP θα ανέφερε ένα σφάλμα ότι η υπογραφή της ήταν διαφορετική από την υπογραφή του γονέα.
Ή όταν περνούσατε μια εξάρτηση στην κλάση `EditFormFactory` μέσω του κατασκευαστή. Αυτό θα προκαλούσε αυτό που ονομάζουμε [κόλαση του κατασκευαστή |dependency-injection:passing-dependencies#Constructor hell].

Είναι γενικά προτιμότερο να προτιμάτε τη [σύνθεση από την κληρονομικότητα |dependency-injection:faq#Why composition is preferred over inheritance].


Χειρισμός φόρμας .[#toc-form-handling]
======================================

Ο χειριστής φόρμας που καλείται μετά από μια επιτυχή υποβολή μπορεί επίσης να είναι μέρος μιας εργοστασιακής κλάσης. Θα λειτουργεί περνώντας τα υποβληθέντα δεδομένα στο μοντέλο για επεξεργασία. Θα μεταβιβάζει τυχόν σφάλματα [πίσω |forms:validation#Processing Errors] στη φόρμα. Το μοντέλο στο ακόλουθο παράδειγμα αντιπροσωπεύεται από την κλάση `Facade`:

```php
class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
		private Facade $facade,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];
		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// επεξεργασία των υποβληθέντων δεδομένων
			$this->facade->process($data);

		} catch (AnyModelException $e) {
			$form->addError('...');
		}
	}
}
```

Αφήστε τον παρουσιαστή να χειριστεί ο ίδιος την ανακατεύθυνση. Θα προσθέσει έναν άλλο χειριστή στο συμβάν `onSuccess`, ο οποίος θα εκτελέσει την ανακατεύθυνση. Αυτό θα επιτρέψει τη χρήση της φόρμας σε διαφορετικούς παρουσιαστές και ο καθένας θα μπορεί να κάνει ανακατεύθυνση σε διαφορετική τοποθεσία.

```php
class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private EditFormFactory $formFactory,
	) {
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->create();
		$form->onSuccess[] = function () {
			$this->flashMessage('Záznam byl uložen');
			$this->redirect('Homepage:');
		};
		return $form;
	}
}
```

Αυτή η λύση εκμεταλλεύεται την ιδιότητα των φορμών ότι, όταν καλείται το `addError()` σε μια φόρμα ή το στοιχείο της, δεν καλείται ο επόμενος χειριστής `onSuccess`.


Κληρονομικότητα από την κλάση Form .[#toc-inheriting-from-the-form-class]
=========================================================================

Μια δομημένη φόρμα δεν πρέπει να είναι παιδί μιας φόρμας. Με άλλα λόγια, μην χρησιμοποιείτε αυτή τη λύση:

```php
// ⛔ ΟΧΙ! Η ΚΛΗΡΟΝΟΜΙΆ ΔΕΝ ΑΝΉΚΕΙ ΕΔΏ
class EditForm extends Form
{
	public function __construct(Translator $translator)
	{
		parent::__construct();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->setTranslator($translator);
	}
}
```

Αντί να δημιουργείτε τη φόρμα στον κατασκευαστή, χρησιμοποιήστε το εργοστάσιο.

Είναι σημαντικό να συνειδητοποιήσετε ότι η κλάση `Form` είναι πρωτίστως ένα εργαλείο για τη συναρμολόγηση μιας φόρμας, δηλαδή ένας κατασκευαστής φόρμας. Και η συναρμολογημένη φόρμα μπορεί να θεωρηθεί το προϊόν της. Ωστόσο, το προϊόν δεν είναι μια ειδική περίπτωση του κατασκευαστή- δεν υπάρχει *είναι μια* σχέση μεταξύ τους, η οποία αποτελεί τη βάση της κληρονομικότητας.


Στοιχείο φόρμας .[#toc-form-component]
======================================

Μια εντελώς διαφορετική προσέγγιση είναι η δημιουργία ενός [συστατικού |application:components] που περιλαμβάνει μια φόρμα. Αυτό δίνει νέες δυνατότητες, για παράδειγμα να αποδώσετε τη φόρμα με συγκεκριμένο τρόπο, αφού το συστατικό περιλαμβάνει ένα πρότυπο.
Ή μπορούν να χρησιμοποιηθούν σήματα για επικοινωνία AJAX και φόρτωση πληροφοριών στη φόρμα, για παράδειγμα για υποδείξεις κ.λπ.


```php
use Nette\Application\UI\Form;

class EditControl extends Nette\Application\UI\Control
{
	public array $onSave = [];

	public function __construct(
		private Facade $facade,
	) {
	}

	protected function createComponentForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// επεξεργασία των υποβληθέντων δεδομένων
			$this->facade->process($data);

		} catch (AnyModelException $e) {
			$form->addError('...');
			return;
		}

		// κλήση συμβάντος
		$this->onSave($this, $data);
	}
}
```

Ας δημιουργήσουμε ένα εργοστάσιο που θα παράγει αυτό το στοιχείο. Αρκεί να [γράψουμε τη διεπαφή του |application:components#Components with Dependencies]:

```php
interface EditControlFactory
{
	function create(): EditControl;
}
```

Και να το προσθέσουμε στο αρχείο ρυθμίσεων:

```neon
services:
	- EditControlFactory
```

Και τώρα μπορούμε να ζητήσουμε το εργοστάσιο και να το χρησιμοποιήσουμε στον παρουσιαστή:

```php
class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private EditControlFactory $controlFactory,
	) {
	}

	protected function createComponentEditForm(): EditControl
	{
		$control = $this->controlFactory->create();

		$control->onSave[] = function (EditControl $control, $data) {
			$this->redirect('this');
			// ή ανακατεύθυνση στο αποτέλεσμα της επεξεργασίας, π.χ.:
			// $this->redirect('detail', ['id' => $data->id]),
		};

		return $control;
	}
}
```

{{sitename: Best Practices}}

Επαναχρησιμοποίηση φορμών σε πολλαπλά σημεία

Στη Nette, έχετε αρκετές επιλογές για να επαναχρησιμοποιήσετε την ίδια φόρμα σε πολλά σημεία χωρίς να αντιγράψετε κώδικα. Σε αυτό το άρθρο, θα εξετάσουμε τις διάφορες λύσεις, συμπεριλαμβανομένων αυτών που πρέπει να αποφύγετε.

Εργοστάσιο φορμών

Μια βασική προσέγγιση για τη χρήση του ίδιου συστατικού σε πολλά σημεία είναι η δημιουργία μιας μεθόδου ή κλάσης που παράγει το συστατικό και στη συνέχεια η κλήση αυτής της μεθόδου σε διαφορετικά σημεία της εφαρμογής. Μια τέτοια μέθοδος ή κλάση ονομάζεται factory. Μην συγχέετε με το πρότυπο σχεδίασης factory method, το οποίο περιγράφει έναν συγκεκριμένο τρόπο χρήσης των εργοστασίων και δεν σχετίζεται με αυτό το θέμα.

Για παράδειγμα, ας δημιουργήσουμε ένα εργοστάσιο που θα δημιουργήσει μια φόρμα επεξεργασίας:

use Nette\Application\UI\Form;

class FormFactory
{
	public function createEditForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Τώρα μπορείτε να χρησιμοποιήσετε αυτό το εργοστάσιο σε διάφορα σημεία της εφαρμογής σας, για παράδειγμα σε παρουσιαστές ή στοιχεία. Και το κάνουμε αυτό ζητώντας το ως εξάρτηση. Έτσι, πρώτα, θα γράψουμε την κλάση στο αρχείο ρυθμίσεων:

services:
	- FormFactory

Και στη συνέχεια τη χρησιμοποιούμε στον παρουσιαστή:

class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->createEditForm();
		$form->onSuccess[] = function () {
			// επεξεργασία των δεδομένων που αποστέλλονται
		};
		return $form;
	}
}

Μπορείτε να επεκτείνετε το εργοστάσιο φορμών με πρόσθετες μεθόδους για να δημιουργήσετε άλλους τύπους φορμών ανάλογα με την εφαρμογή σας. Και, φυσικά, μπορείτε να προσθέσετε μια μέθοδο που δημιουργεί μια βασική φόρμα χωρίς στοιχεία, την οποία θα χρησιμοποιούν οι άλλες μέθοδοι:

class FormFactory
{
	public function createForm(): Form
	{
		$form = new Form;
		return $form;
	}

	public function createEditForm(): Form
	{
		$form = $this->createForm();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Η μέθοδος createForm() δεν κάνει τίποτα χρήσιμο ακόμα, αλλά αυτό θα αλλάξει γρήγορα.

Εξαρτήσεις εργοστασίων

Με τον καιρό, θα γίνει προφανές ότι χρειαζόμαστε τις φόρμες να είναι πολύγλωσσες. Αυτό σημαίνει ότι πρέπει να δημιουργήσουμε έναν μεταφραστή για όλες τις φόρμες. Για να το κάνουμε αυτό, τροποποιούμε την κλάση FormFactory ώστε να δέχεται το αντικείμενο Translator ως εξάρτηση στον κατασκευαστή και να το περνάει στη φόρμα:

use Nette\Localization\Translator;

class FormFactory
{
	public function __construct(
		private Translator $translator,
	) {
	}

	public function createForm(): Form
	{
		$form = new Form;
		$form->setTranslator($this->translator);
		return $form;
	}

	//...
}

Δεδομένου ότι η μέθοδος createForm() καλείται και από άλλες μεθόδους που δημιουργούν συγκεκριμένες φόρμες, χρειάζεται να ορίσουμε τον μεταφραστή μόνο σε αυτή τη μέθοδο. Και τελειώσαμε. Δεν χρειάζεται να αλλάξουμε τον κώδικα του παρουσιαστή ή του συστατικού, πράγμα που είναι υπέροχο.

Περισσότερες εργοστασιακές κλάσεις

Εναλλακτικά, μπορείτε να δημιουργήσετε πολλαπλές κλάσεις για κάθε φόρμα που θέλετε να χρησιμοποιήσετε στην εφαρμογή σας. Αυτή η προσέγγιση μπορεί να αυξήσει την αναγνωσιμότητα του κώδικα και να διευκολύνει τη διαχείριση των φορμών. Αφήστε το αρχικό FormFactory για να δημιουργήσετε μόνο μια καθαρή φόρμα με βασικές ρυθμίσεις (για παράδειγμα, με υποστήριξη μετάφρασης) και δημιουργήστε ένα νέο εργοστάσιο EditFormFactory για τη φόρμα επεξεργασίας.

class FormFactory
{
	public function __construct(
		private Translator $translator,
	) {
	}

	public function create(): Form
	{
		$form = new Form;
		$form->setTranslator($this->translator);
		return $form;
	}
}


// ✅ χρήση της σύνθεσης
class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		// εδώ προστίθενται πρόσθετα πεδία φόρμας
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Είναι πολύ σημαντικό ότι η σύνδεση μεταξύ των κλάσεων FormFactory και EditFormFactory υλοποιείται με σύνθεση και όχι με κληρονομικότητα αντικειμένων:

// ⛔ ΟΧΙ! Η ΚΛΗΡΟΝΟΜΙΆ ΔΕΝ ΑΝΉΚΕΙ ΕΔΏ
class EditFormFactory extends FormFactory
{
	public function create(): Form
	{
		$form = parent::create();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Η χρήση κληρονομικότητας σε αυτή την περίπτωση θα ήταν εντελώς αντιπαραγωγική. Θα αντιμετωπίζατε προβλήματα πολύ γρήγορα. Για παράδειγμα, αν θέλατε να προσθέσετε παραμέτρους στη μέθοδο create(), η PHP θα ανέφερε ένα σφάλμα ότι η υπογραφή της ήταν διαφορετική από την υπογραφή του γονέα. Ή όταν περνούσατε μια εξάρτηση στην κλάση EditFormFactory μέσω του κατασκευαστή. Αυτό θα προκαλούσε αυτό που ονομάζουμε κόλαση του κατασκευαστή.

Είναι γενικά προτιμότερο να προτιμάτε τη σύνθεση από την κληρονομικότητα.

Χειρισμός φόρμας

Ο χειριστής φόρμας που καλείται μετά από μια επιτυχή υποβολή μπορεί επίσης να είναι μέρος μιας εργοστασιακής κλάσης. Θα λειτουργεί περνώντας τα υποβληθέντα δεδομένα στο μοντέλο για επεξεργασία. Θα μεταβιβάζει τυχόν σφάλματα πίσω στη φόρμα. Το μοντέλο στο ακόλουθο παράδειγμα αντιπροσωπεύεται από την κλάση Facade:

class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
		private Facade $facade,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];
		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// επεξεργασία των υποβληθέντων δεδομένων
			$this->facade->process($data);

		} catch (AnyModelException $e) {
			$form->addError('...');
		}
	}
}

Αφήστε τον παρουσιαστή να χειριστεί ο ίδιος την ανακατεύθυνση. Θα προσθέσει έναν άλλο χειριστή στο συμβάν onSuccess, ο οποίος θα εκτελέσει την ανακατεύθυνση. Αυτό θα επιτρέψει τη χρήση της φόρμας σε διαφορετικούς παρουσιαστές και ο καθένας θα μπορεί να κάνει ανακατεύθυνση σε διαφορετική τοποθεσία.

class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private EditFormFactory $formFactory,
	) {
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->create();
		$form->onSuccess[] = function () {
			$this->flashMessage('Záznam byl uložen');
			$this->redirect('Homepage:');
		};
		return $form;
	}
}

Αυτή η λύση εκμεταλλεύεται την ιδιότητα των φορμών ότι, όταν καλείται το addError() σε μια φόρμα ή το στοιχείο της, δεν καλείται ο επόμενος χειριστής onSuccess.

Κληρονομικότητα από την κλάση Form

Μια δομημένη φόρμα δεν πρέπει να είναι παιδί μιας φόρμας. Με άλλα λόγια, μην χρησιμοποιείτε αυτή τη λύση:

// ⛔ ΟΧΙ! Η ΚΛΗΡΟΝΟΜΙΆ ΔΕΝ ΑΝΉΚΕΙ ΕΔΏ
class EditForm extends Form
{
	public function __construct(Translator $translator)
	{
		parent::__construct();
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->setTranslator($translator);
	}
}

Αντί να δημιουργείτε τη φόρμα στον κατασκευαστή, χρησιμοποιήστε το εργοστάσιο.

Είναι σημαντικό να συνειδητοποιήσετε ότι η κλάση Form είναι πρωτίστως ένα εργαλείο για τη συναρμολόγηση μιας φόρμας, δηλαδή ένας κατασκευαστής φόρμας. Και η συναρμολογημένη φόρμα μπορεί να θεωρηθεί το προϊόν της. Ωστόσο, το προϊόν δεν είναι μια ειδική περίπτωση του κατασκευαστή- δεν υπάρχει είναι μια σχέση μεταξύ τους, η οποία αποτελεί τη βάση της κληρονομικότητας.

Στοιχείο φόρμας

Μια εντελώς διαφορετική προσέγγιση είναι η δημιουργία ενός συστατικού που περιλαμβάνει μια φόρμα. Αυτό δίνει νέες δυνατότητες, για παράδειγμα να αποδώσετε τη φόρμα με συγκεκριμένο τρόπο, αφού το συστατικό περιλαμβάνει ένα πρότυπο. Ή μπορούν να χρησιμοποιηθούν σήματα για επικοινωνία AJAX και φόρτωση πληροφοριών στη φόρμα, για παράδειγμα για υποδείξεις κ.λπ.

use Nette\Application\UI\Form;

class EditControl extends Nette\Application\UI\Control
{
	public array $onSave = [];

	public function __construct(
		private Facade $facade,
	) {
	}

	protected function createComponentForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// πρόσθετα πεδία φόρμας προστίθενται εδώ
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// επεξεργασία των υποβληθέντων δεδομένων
			$this->facade->process($data);

		} catch (AnyModelException $e) {
			$form->addError('...');
			return;
		}

		// κλήση συμβάντος
		$this->onSave($this, $data);
	}
}

Ας δημιουργήσουμε ένα εργοστάσιο που θα παράγει αυτό το στοιχείο. Αρκεί να γράψουμε τη διεπαφή του:

interface EditControlFactory
{
	function create(): EditControl;
}

Και να το προσθέσουμε στο αρχείο ρυθμίσεων:

services:
	- EditControlFactory

Και τώρα μπορούμε να ζητήσουμε το εργοστάσιο και να το χρησιμοποιήσουμε στον παρουσιαστή:

class MyPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private EditControlFactory $controlFactory,
	) {
	}

	protected function createComponentEditForm(): EditControl
	{
		$control = $this->controlFactory->create();

		$control->onSave[] = function (EditControl $control, $data) {
			$this->redirect('this');
			// ή ανακατεύθυνση στο αποτέλεσμα της επεξεργασίας, π.χ.:
			// $this->redirect('detail', ['id' => $data->id]),
		};

		return $control;
	}
}