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, bool $throw=true): ?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. If no matching object is found, it throws an exception; pass false as the second argument to return null instead. If you pass null as the $type, the method searches for the topmost component in the tree, i.e., the root with no parent.

lookupPath (?string $type=null, bool $throw=true): ?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. When $type is null (or omitted), the path is measured up to the root of the tree.

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. Descendants that use the ArrayAccess trait (such as Control and Presenter) also allow accessing children via array notation, e.g. $container['child'].

addComponent (Component $component, ?string $name, ?string $insertBefore=null)static

Adds a component to the container as a child. If $name is null, the component's own name is used. Using the optional $insertBefore – the name of an existing child – the new component is inserted right before it; otherwise it is appended to the end. The method returns the container itself, so calls can be chained.

removeComponent (Component $component)void

Removes a child component from the container.

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(): IComponent[]

Returns direct descendants as an array; the keys contain the names of these components. To retrieve the entire subtree recursively, use getComponentTree(), optionally combined with array_filter() for type filtering. (The $deep and $filterType parameters known from older versions were removed in version 4.0.)

getComponentTree(): list<IComponent>

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 can a component find out the moment it is attached below a presenter – or below any other ancestor of a given type? Watching the direct parent isn't enough, because the connection may happen higher up the tree, for example when the parent's parent gets attached. That is what the monitor($type, $attached, $detached) method is for: a component declares that it wants to be notified whenever an ancestor of class or interface $type appears above it in the tree, or disappears from it. A component can monitor any number of types; the $attached callback fires when a matching ancestor connects and receives that ancestor as its argument, while $detached fires when it disconnects. Monitoring can be stopped again with unmonitor($type).

Notifications follow the tree structure. When attaching, an ancestor is notified before its descendants (top-down), so a parent can prepare shared state first, or even remove a child before the child's own callback runs. When detaching, the order is reversed – descendants are notified first. Callbacks are also deduplicated, so the same callback is never called twice for the same object. For the reasoning behind this behavior, see the blog post about version 4.0.

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.

version: 4.x 4.0 3.x