Nette Documentation Preview

syntax
Reusing Forms in Multiple Places
********************************

.[perex]
In Nette, you have several options to reuse the same form in multiple places without duplicating code. In this article, we'll go over the different solutions, including the ones you should avoid.


Form Factory
============

One basic approach to using the same component in multiple places is to create a method or class that generates the component, and then call that method in different places in the application. Such a method or class is called a *factory*. Please do not confuse with the *factory method* design pattern, which describes a specific way of using factories and is not related to this topic.

As an example, let's create a factory that will build an edit form:

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

class FormFactory
{
	public function createEditForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Now you can use this factory in different places in your application, for example in presenters or components. And we do this by [requesting it as a dependency |dependency-injection:passing-dependencies]. So first, we'll write the class to the configuration file:

```neon
services:
	- FormFactory
```

And then we use it in the presenter:


```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 () {
			// processing of sent data
		};
		return $form;
	}
}
```

You can extend the form factory with additional methods to create other types of forms to suit your application. And, of course, you can add a method that creates a basic form without elements, which the other methods will use:

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

	public function createEditForm(): Form
	{
		$form = $this->createForm();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

The `createForm()` method doesn't do anything useful yet, but that will change quickly.


Factory Dependencies
====================

In time, it will become apparent that we need forms to be multilingual. This means that we need to set up a [translator |forms:rendering#Translating] for all forms. To do this, we modify the `FormFactory` class to accept the `Translator` object as a dependency in the constructor, and pass it to the form:

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

	// ...
}
```

Since the `createForm()` method is also called by other methods that create specific forms, we only need to set the translator in that method. And we're done. No need to change any presenter or component code, which is great.


More Factory Classes
====================

Alternatively, you can create multiple classes for each form you want to use in your application.
This approach can increase code readability and make forms easier to manage. Leave the original `FormFactory` to create just a pure form with basic configuration (for example, with translation support) and create a new factory `EditFormFactory` for the edit form.

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

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


// ✅ use of composition
class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

It is very important that the binding between the `FormFactory` and `EditFormFactory` classes is implemented [by composition |nette:introduction-to-object-oriented-programming#composition], not [object inheritance |https://doc.nette.org/en/introduction-to-object-oriented-programming#inheritance]:

```php
// ⛔ NO! INHERITANCE DOESN'T BELONG HERE
class EditFormFactory extends FormFactory
{
	public function create(): Form
	{
		$form = parent::create();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}
```

Using inheritance in this case would be completely counterproductive. You would run into problems very quickly. For example, if you wanted to add parameters to the `create()` method; PHP would report an error that its signature was different from the parent.
Or when passing a dependency to the `EditFormFactory` class via the constructor. This would cause what we call [constructor hell |dependency-injection:passing-dependencies#Constructor hell].

It is generally better to prefer [composition over inheritance |dependency-injection:faq#Why composition is preferred over inheritance].


Form Handling
=============

The form handler that is called after a successful submission can also be part of a factory class. It will work by passing the submitted data to the model for processing. It will pass any errors [back to |forms:validation#Processing Errors] the form. The model in the following example is represented by the class `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:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];
		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// processing of submitted data
			$this->facade->process($data);

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

Let the presenter handle the redirection itself. It will add another handler to the `onSuccess` event, which will perform the redirection. This will allow the form to be used in different presenters, and each can redirect to a different location.

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

This solution takes advantage of the property of forms that, when `addError()` is called on a form or its element, the next `onSuccess` handler is not invoked.


Inheriting from the Form Class
==============================

A built form is not supposed to be a child of a form. In other words, don't use this solution:

```php
// ⛔ NO! INHERITANCE DOESN'T BELONG HERE
class EditForm extends Form
{
	public function __construct(Translator $translator)
	{
		parent::__construct();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->setTranslator($translator);
	}
}
```

Instead of building the form in the constructor, use the factory.

It's important to realize that the `Form` class is primarily a tool for assembling a form, i.e., a form builder. And the assembled form can be considered its product. However, the product is not a specific case of the builder; there is no *is a* relationship between them, which forms the basis of inheritance.


Form Component
==============

A completely different approach is to create a [component |application:components] that includes a form. This gives new possibilities, for example to render the form in a specific way, since the component includes a template.
Or signals can be used for AJAX communication and loading information into the form, for example for hinting, etc.


```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:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// processing of submitted data
			$this->facade->process($data);

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

		// event invocation
		$this->onSave($this, $data);
	}
}
```

Let's create a factory that will produce this component. It's enough to [write its interface|application:components#Components with Dependencies]:

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

And add it to the configuration file:

```neon
services:
	- EditControlFactory
```

And now we can request the factory and use it in the presenter:

```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');
			// or redirect to the result of editing, e.g.:
			// $this->redirect('detail', ['id' => $data->id]);
		};

		return $control;
	}
}
```

{{sitename: Best Practices}}

Reusing Forms in Multiple Places

In Nette, you have several options to reuse the same form in multiple places without duplicating code. In this article, we'll go over the different solutions, including the ones you should avoid.

Form Factory

One basic approach to using the same component in multiple places is to create a method or class that generates the component, and then call that method in different places in the application. Such a method or class is called a factory. Please do not confuse with the factory method design pattern, which describes a specific way of using factories and is not related to this topic.

As an example, let's create a factory that will build an edit form:

use Nette\Application\UI\Form;

class FormFactory
{
	public function createEditForm(): Form
	{
		$form = new Form;
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Now you can use this factory in different places in your application, for example in presenters or components. And we do this by requesting it as a dependency. So first, we'll write the class to the configuration file:

services:
	- FormFactory

And then we use it in the presenter:

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

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->createEditForm();
		$form->onSuccess[] = function () {
			// processing of sent data
		};
		return $form;
	}
}

You can extend the form factory with additional methods to create other types of forms to suit your application. And, of course, you can add a method that creates a basic form without elements, which the other methods will use:

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

	public function createEditForm(): Form
	{
		$form = $this->createForm();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

The createForm() method doesn't do anything useful yet, but that will change quickly.

Factory Dependencies

In time, it will become apparent that we need forms to be multilingual. This means that we need to set up a translator for all forms. To do this, we modify the FormFactory class to accept the Translator object as a dependency in the constructor, and pass it to the form:

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;
	}

	// ...
}

Since the createForm() method is also called by other methods that create specific forms, we only need to set the translator in that method. And we're done. No need to change any presenter or component code, which is great.

More Factory Classes

Alternatively, you can create multiple classes for each form you want to use in your application. This approach can increase code readability and make forms easier to manage. Leave the original FormFactory to create just a pure form with basic configuration (for example, with translation support) and create a new factory EditFormFactory for the edit form.

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

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


// ✅ use of composition
class EditFormFactory
{
	public function __construct(
		private FormFactory $formFactory,
	) {
	}

	public function create(): Form
	{
		$form = $this->formFactory->create();
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

It is very important that the binding between the FormFactory and EditFormFactory classes is implemented by composition, not object inheritance:

// ⛔ NO! INHERITANCE DOESN'T BELONG HERE
class EditFormFactory extends FormFactory
{
	public function create(): Form
	{
		$form = parent::create();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		return $form;
	}
}

Using inheritance in this case would be completely counterproductive. You would run into problems very quickly. For example, if you wanted to add parameters to the create() method; PHP would report an error that its signature was different from the parent. Or when passing a dependency to the EditFormFactory class via the constructor. This would cause what we call constructor hell.

It is generally better to prefer composition over inheritance.

Form Handling

The form handler that is called after a successful submission can also be part of a factory class. It will work by passing the submitted data to the model for processing. It will pass any errors back to the form. The model in the following example is represented by the class Facade:

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

	public function create(): Form
	{
		$form = $this->formFactory->create();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];
		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// processing of submitted data
			$this->facade->process($data);

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

Let the presenter handle the redirection itself. It will add another handler to the onSuccess event, which will perform the redirection. This will allow the form to be used in different presenters, and each can redirect to a different location.

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;
	}
}

This solution takes advantage of the property of forms that, when addError() is called on a form or its element, the next onSuccess handler is not invoked.

Inheriting from the Form Class

A built form is not supposed to be a child of a form. In other words, don't use this solution:

// ⛔ NO! INHERITANCE DOESN'T BELONG HERE
class EditForm extends Form
{
	public function __construct(Translator $translator)
	{
		parent::__construct();
		$form->addText('title', 'Title:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->setTranslator($translator);
	}
}

Instead of building the form in the constructor, use the factory.

It's important to realize that the Form class is primarily a tool for assembling a form, i.e., a form builder. And the assembled form can be considered its product. However, the product is not a specific case of the builder; there is no is a relationship between them, which forms the basis of inheritance.

Form Component

A completely different approach is to create a component that includes a form. This gives new possibilities, for example to render the form in a specific way, since the component includes a template. Or signals can be used for AJAX communication and loading information into the form, for example for hinting, etc.

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:');
		// additional form fields are added here
		$form->addSubmit('send', 'Save');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $data): void
	{
		try {
			// processing of submitted data
			$this->facade->process($data);

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

		// event invocation
		$this->onSave($this, $data);
	}
}

Let's create a factory that will produce this component. It's enough to write its interface:

interface EditControlFactory
{
	function create(): EditControl;
}

And add it to the configuration file:

services:
	- EditControlFactory

And now we can request the factory and use it in the presenter:

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');
			// or redirect to the result of editing, e.g.:
			// $this->redirect('detail', ['id' => $data->id]);
		};

		return $control;
	}
}