Модель компонента
Важным понятием в 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
).