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