Модель компонента

Важным понятием в Nette является компонент. Мы вставляем визуальные интерактивные компоненты на страницы, формы или все их элементы также являются компонентами. Есть два основных класса, от которых наследуются все эти компоненты, они входят в пакет nette/component-model и отвечают за создание иерархии дерева компонентов.

Component

Nette\ComponentModel\Component является общим предком всех компонентов. Он содержит метод getName(), возвращающий имя компонента, и метод getParent(), возвращающий его родителя. Оба параметра могут быть заданы с помощью метода setParent() – первый параметр – родитель, второй – имя компонента.

lookup(string $type): ?Component

Ищет в иерархии объект нужного класса или интерфейса. Например, $component->lookup(Nette\Application\UI\Presenter::class) возвращает presenter, если компонент связан с ним, несмотря на несколько уровней.

lookupPath(string $type): ?string

Возвращает так называемый путь, который представляет собой строку, образованную путем конкатенации имен всех компонентов на пути между текущим компонентом и искомым компонентом. Так, например, $component->lookupPath(Nette\Application\UI\Presenter::class) возвращает уникальный идентификатор компонента относительно ведущего.

Container

Nette\ComponentModel\Container является родительским компонентом, т.е. компонентом, содержащим дочерние компоненты и, таким образом, формирующим древовидную структуру. Он имеет методы для легкого добавления, извлечения и удаления компонентов. Он является предком, например, формы или классов Control и Presenter.

getComponent(string $name): ?Component

Возвращает компонент. Попытка вызова неопределенного дочернего компонента приводит к вызову фабрики createComponent($name). Метод createComponent($name) вызывает метод createComponent<component name> в текущем компоненте и передает имя компонента в качестве параметра. Созданный компонент затем передается текущему компоненту как его дочерний компонент. Мы называем эти фабрики компонентов, они могут быть реализованы в классах, унаследованных от Container.

getComponents(): array

Возвращает прямых потомков в виде массива. Ключи содержат имена этих компонентов. Примечание: в версии 3.0.x метод возвращал итератор вместо массива, а его первый параметр указывал, нужно ли выполнять глубокий итерационный просмотр компонентов, а второй представлял собой фильтр типов. Эти параметры устарели.

getComponentTree(): array

Возвращает всю иерархию компонентов, включая все вложенные дочерние компоненты, в виде индексированного массива. Поиск идет сначала в глубину.

Мониторинг предков

Модель компонентов Nette позволяет очень динамично работать с деревом (мы можем удалять, перемещать, добавлять компоненты), поэтому было бы ошибкой полагаться на то, что после создания компонента родитель, родитель родителя и т.д. известны сразу (в конструкторе). Обычно родитель вообще не известен в момент создания компонента.

Как узнать, когда компонент был добавлен в дерево презентера? Следить за изменением родителя недостаточно, потому что родитель родителя мог быть присоединен, например, к презентеру. В этом может помочь метод monitor($type, $attached, $detached). Каждый компонент может контролировать любое количество классов и интерфейсов. Подключение или отключение объявляется вызовом обратных вызовов $attached и $detached, соответственно, и передачей объекта контролируемого класса.

Пример: Класс UploadControl, представляющий элемент формы для загрузки файлов в Nette Forms, должен установить атрибут формы enctype в значение multipart/form-data. Но во время создания объекта он не должен быть привязан ни к какой форме. Когда модифицировать форму? Решение простое – создаем запрос на мониторинг в конструкторе:

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');
		});
		// ...
	}

	// ...
}

, и когда форма становится доступной, вызывается обратный вызов. (Ранее вместо этого использовались обычные методы attached и detached ).

версия: 3.x