Nette Documentation Preview

syntax
Модел на компонента
*******************

.[perex]
Важно понятие в Nette е компонентът. Вмъкваме [визуални интерактивни компоненти |application:components] в страници, формуляри или всички техни елементи също са компоненти. Има два основни класа, от които всички тези компоненти наследяват, те са част от пакета `nette/component-model` и отговарят за създаването на йерархията на дървото на компонентите.


Component
=========
[api:Nette\ComponentModel\Component] е общият предшественик на всички компоненти. Той съдържа метод `getName()`, който връща името на компонента, и метод `getParent()`, който връща неговия родител. И двата параметъра могат да бъдат зададени чрез метода `setParent()` - първият параметър е родителят, а вторият е името на компонента.


lookup(string $type): ?Component .[method]
------------------------------------------
Търси в йерархията обект от желания клас или интерфейс. Например `$component->lookup(Nette\Application\UI\Presenter::class)` връща presenter, ако компонент е свързан с него въпреки няколко нива.


lookupPath(string $type): ?string .[method]
-------------------------------------------
Връща т.нар. път, който представлява низ, образуван от сбиването на имената на всички компоненти в пътя между текущия компонент и търсения компонент. Така например `$component->lookupPath(Nette\Application\UI\Presenter::class)` връща уникален идентификатор на компонент спрямо главния.


Container
=========
[api:Nette\ComponentModel\Container] е родителски компонент, т.е. компонент, който съдържа дъщерни компоненти и по този начин образува дървовидна структура. Той разполага с методи за лесно добавяне, извличане и отстраняване на компоненти. Той е родоначалник например на формата или класовете `Control` и `Presenter`.


getComponent(string $name): ?Component .[method]
------------------------------------------------
Връща компонент. Опитът за извикване на недефиниран дъщерен компонент води до извикване на factory [createComponent($name |api:Nette\ComponentModel\Container::createComponent()]). Методът `createComponent($name)` извиква метода `createComponent<component name>` в текущия компонент и предава името на компонента като параметър. След това създаденият компонент се предава на текущия компонент като негов дъщерен компонент. Наричаме тези фабрики за компоненти, като те могат да бъдат реализирани в класове, наследени от `Container`.


getComponents(): array .[method]
--------------------------------
Връща преките наследници като масив. Ключовете съдържат имената на тези компоненти. Забележка: във версия 3.0.x методът връщаше итератор вместо масив, като първият му параметър определяше дали да се итерира през компонентите в дълбочина, а вторият представляваше филтър на типа. Тези параметри са отпаднали.


getComponentTree(): array .[method]{data-version:3.1.0}
-------------------------------------------------------
Връща цялата йерархия от компоненти, включително всички вложени дъщерни компоненти, като индексиран масив. Търсенето се извършва първо в дълбочина.


Мониторинг на предците .[#toc-monitoring-of-ancestors]
======================================================

Компонентният модел на Nette позволява много динамична работа с дървото (можем да изтриваме, преместваме, добавяме компоненти), така че би било грешка да разчитаме на факта, че след създаването на компонент родителят, родителят и т.н. са известни веднага (в конструктора). Обикновено родителят изобщо не е известен при създаването на компонента.

Как да разберем, че даден компонент е бил добавен в дървото на презентатора? Не е достатъчно да се следи промяната на родителя, защото той може да е бил прикрепен към водещия, например. За това може да помогне методът [monitor($type, $attached, $detached) |api:Nette\ComponentModel\Component::monitor()]. Всеки компонент може да наблюдава произволен брой класове и интерфейси. Връзката или прекъсването на връзката се декларира чрез извикване на обратните извиквания `$attached` и `$detached`, съответно, и предаване на обект от наблюдавания клас.

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

```php
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`.)


{{leftbar: nette:@menu-topics}}

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

Важно понятие в 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

Връща компонент. Опитът за извикване на недефиниран дъщерен компонент води до извикване на factory 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.)