Model komponentu

Ważnym pojęciem w Nette jest komponent. Do stron wstawiamy wizualne interaktywne kompon enty, formularze lub wszystkie ich elementy to również komponenty. Istnieją dwie podstawowe klasy, z których dziedziczą wszystkie te komponenty, wchodzą w skład pakietu nette/component-model i odpowiadają za tworzenie hierarchii drzewa komponentów.

Component

Nette\ComponentModel\Component jest wspólnym przodkiem wszystkich komponentów. Zawiera ona metodę getName() zwracającą nazwę komponentu oraz metodę getParent() zwracającą jego rodzica. Oba można ustawić za pomocą metody setParent() – pierwszy parametr to rodzic, a drugi to nazwa komponentu.

lookup (string $type): ?Component

Przeszukuje hierarchię w poszukiwaniu obiektu żądanej klasy lub interfejsu. Na przykład $component->lookup(Nette\Application\UI\Presenter::class) zwraca prezentera, jeśli komponent jest z nim połączony, pomimo kilku poziomów.

lookupPath (string $type): ?string

Zwraca tzw. ścieżkę, czyli ciąg utworzony przez konkatenację nazw wszystkich komponentów na ścieżce pomiędzy bieżącym komponentem a poszukiwanym komponentem. Tak więc, na przykład, $component->lookupPath(Nette\Application\UI\Presenter::class) zwraca unikalny identyfikator komponentu względem prezentera.

Container

Nette\ComponentModel\Container jest składnikiem nadrzędnym, czyli składnikiem zawierającym dzieci, a więc tworzącym strukturę drzewa. Posiada metody umożliwiające łatwe dodawanie, pobieranie i usuwanie obiektów. Jest przodkiem np. formy lub klas Control i Presenter.

getComponent (string $name): ?Component

Zwraca element. Podczas próby uzyskania niezdefiniowanego dziecka wywoływana jest fabryka createComponent($name). Metoda createComponent($name) wywołuje metodę w bieżącym komponencie createComponent<název komponenty> i przekazuje nazwę komponentu jako parametr. Utworzony komponent jest następnie dodawany do bieżącego komponentu jako jego dziecko. Metody te nazywane są fabrykami komponentów i mogą być implementowane przez potomków klasy Container.

getComponents(): array

Zwraca bezpośrednich potomków jako tablicę. Klucze zawierają nazwy tych komponentów. Uwaga: w wersji 3.0.x metoda zwracała iterator zamiast tablicy, a jej pierwszy parametr określał, czy iterować przez komponenty w głąb, a drugi reprezentował filtr typu. Te parametry są przestarzałe.

getComponentTree(): array

Zwraca całą hierarchię komponentów, w tym wszystkie zagnieżdżone komponenty podrzędne, jako indeksowaną tablicę. Wyszukiwanie odbywa się najpierw w głąb.

Monitorowanie przodków

Model komponentów Nette pozwala na bardzo dynamiczną pracę z drzewem (możemy usuwać, przenosić, dodawać komponenty), więc błędem byłoby poleganie na tym, że po utworzeniu komponentu od razu (w konstruktorze) znany jest jego rodzic, rodzic rodzica itd. Zazwyczaj rodzic nie jest w ogóle znany w momencie tworzenia komponentu.

Jak dowiedzieć się, kiedy komponent został dodany do drzewa prezentera? Śledzenie zmiany rodzica nie wystarcza, bo rodzic rodzica mógł zostać dołączony np. do prezentera. Pomóc może metoda monitor($type, $attached, $detached). Każdy komponent może monitorować dowolną liczbę klas i interfejsów. Połączenie lub rozłączenie ogłaszane jest poprzez wywołanie callbacków odpowiednio $attached i $detached, i przekazanie obiektu monitorowanej klasy.

Aby lepiej zrozumieć przykład, klasa UploadControl, reprezentująca element formularza do przesyłania plików w Nette Forms, musi ustawić atrybut formularza enctype na multipart/form-data. Nie musi jednak być dołączona do żadnego formularza w momencie tworzenia obiektu. W jakim więc momencie modyfikować formularz? Rozwiązanie jest proste – konstruktor prosi o monitorowanie:

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

	// ...
}

i gdy formularz jest dostępny, wywoływane jest wywołanie zwrotne. (Wcześniej zamiast tego używano wspólnych metod attached i detached).

wersja: 3.x