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)` връща презентер, ако компонентът е свързан с него, дори през няколко нива.


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


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


getComponent(string $name): ?Component .[method]
------------------------------------------------
Връща компонент. При опит за получаване на недефиниран наследник се извиква фабриката `createComponent($name)`. Методът `createComponent($name)` извиква в текущия компонент метода `createComponent<име на компонента>` и като параметър му предава името на компонента. Създаденият компонент след това се добавя към текущия компонент като негов наследник. Тези методи наричаме фабрики за компоненти и могат да бъдат имплементирани от наследниците на класа `Container`.


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


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


Наблюдение на предците
======================

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

Как да разберем кога компонентът е бил прикрепен към дървото на презентера? Наблюдението на промяната на родителя не е достатъчно, тъй като към презентера може да е бил прикрепен например родителят на родителя. Помага методът [monitor($type, $attached, $detached)|api:Nette\ComponentModel\Component::monitor()]. Всеки компонент може да наблюдава произволен брой класове и интерфейси. Прикрепването или откачането се съобщава чрез извикване на callback `$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');
		});
		// ...
	}

	// ...
}
```

и щом формата е налична, се извиква callback. (Преди това вместо него се използваха общите методи `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) връща презентер, ако компонентът е свързан с него, дори през няколко нива.

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<име на компонента> и като параметър му предава името на компонента. Създаденият компонент след това се добавя към текущия компонент като негов наследник. Тези методи наричаме фабрики за компоненти и могат да бъдат имплементирани от наследниците на класа Container.

getComponents(): array

Връща преките наследници като масив. Ключовете съдържат имената на тези компоненти. Забележка: във версия 3.0.x методът връщаше итератор вместо масив и първият му параметър определяше дали компонентите да се обхождат в дълбочина, а вторият представляваше типов филтър. Тези параметри са deprecated.

getComponentTree(): array

Получава цялата йерархия на компоненти, включително всички вложени подчинени компоненти, като индексиран масив. Търсенето се извършва първо в дълбочина.

Наблюдение на предците

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

Как да разберем кога компонентът е бил прикрепен към дървото на презентера? Наблюдението на промяната на родителя не е достатъчно, тъй като към презентера може да е бил прикрепен например родителят на родителя. Помага методът monitor($type, $attached, $detached). Всеки компонент може да наблюдава произволен брой класове и интерфейси. Прикрепването или откачането се съобщава чрез извикване на callback $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');
		});
		// ...
	}

	// ...
}

и щом формата е налична, се извиква callback. (Преди това вместо него се използваха общите методи attached, респ. detached).