Component Model

An important concept in Nette is the component. We insert visual interactive components into pages; forms and all their elements are also components. The two basic classes from which all these components inherit are part of the nette/component-model package and are responsible for creating the component tree hierarchy.

Component

Nette\ComponentModel\Component is the common ancestor of all components. It contains the getName() method returning the name of the component and the getParent() method returning its parent. Both can be set using the setParent() method – the first parameter is the parent, and the second is the component name.

lookup (string $type): ?Component

Searches up the hierarchy for an object of the desired class or interface. For example, $component->lookup(Nette\Application\UI\Presenter::class) returns the presenter if the component is connected to it, even across several levels.

lookupPath (string $type): ?string

Returns the so-called path, which is a string formed by concatenating the names of all components on the path between the current component and the component being searched for. So, for example, $component->lookupPath(Nette\Application\UI\Presenter::class) returns the unique identifier of the component relative to the presenter.

Container

Nette\ComponentModel\Container is the parent component, i.e., the component containing children and thus forming the tree structure. It has methods for easily adding, retrieving, and removing objects. It is the ancestor of, for example, the form or classes Control and Presenter.

getComponent (string $name): ?Component

Returns a component. Attempting to retrieve an undefined child invokes the factory method createComponent($name). The createComponent($name) method calls the method createComponent<component name> in the current component, passing the component name as a parameter. The created component is then added to the current component as its child. We call these methods component factories, and they can be implemented in classes inherited from Container.

getComponents(): array

Returns direct descendants as an array. The keys contain the names of these components. Note: in version 3.0.x, the method returned an iterator instead of an array, and its first parameter specified whether to iterate through the components in depth, and the second represented a type filter. These parameters are deprecated.

getComponentTree(): array

Gets the entire hierarchy of components, including all nested child components, as an indexed array. The search is depth-first.

Monitoring Ancestors

The Nette component model allows for very dynamic work with the tree (we can remove, move, add components), so it would be a mistake to rely on the fact that after creating a component, the parent, parent's parent, etc., are known immediately (in the constructor). Usually, the parent is not known at all when the component is created.

How to find out when a component has been added to the presenter tree? Keeping track of the parent change is not enough, because the parent of the parent could have been attached to the presenter, for example. The monitor($type, $attached, $detached) method can help. Each component can monitor any number of classes and interfaces. Connection or disconnection is announced by calling the callbacks $attached and $detached, respectively, and passing the object of the monitored class.

For better understanding, here's an example: The UploadControl class, representing the form control for uploading files in Nette Forms, must set the form's enctype attribute to multipart/form-data. However, at the time the object is created, it might not be attached to any form. So, at what point should the form be modified? The solution is simple – a request for monitoring is made in the constructor:

class UploadControl extends Nette\Forms\Controls\BaseControl
{
	public function __construct($label)
	{
		$this->monitor(Nette\Forms\Form::class, function ($form): void {
			$form->setHtmlAttribute('enctype', 'multipart/form-data');
		});
		// ...
	}

	// ...
}

and as soon as the form becomes available, the callback is invoked. (Previously, the common methods attached and detached were used for this purpose.)

version: 3.x