Bileşen Modeli
Nette'de önemli bir kavram bileşendir. Sayfalara görsel etkileşimli bileşenler ekleriz; formlar ve onların tüm
elemanları da bileşendir. Tüm bu bileşenlerin kalıttığı iki temel sınıf nette/component-model paketinin
parçasıdır ve bileşen ağacı hiyerarşisini oluşturmaktan sorumludur.
Component
Nette\ComponentModel\Component,
tüm bileşenlerin ortak atasıdır. Bileşenin adını döndüren getName() metodunu ve anasını döndüren
getParent() metodunu içerir. İkisi de setParent() metoduyla ayarlanabilir; ilk parametre ana, ikincisi
ise bileşen adıdır.
lookup (?string $type, bool $throw=true): ?Component
Hiyerarşide yukarı doğru, istenen sınıf ya da arayüzden bir nesne arar. Örneğin
$component->lookup(Nette\Application\UI\Presenter::class), bileşen bir presenter'a bağlıysa, birkaç düzey
ötede olsa bile onu döndürür. Eşleşen bir nesne bulunamazsa istisna fırlatır; onun yerine null döndürmesi
için ikinci argüman olarak false aktarın. $type olarak null aktarırsanız, metot
ağaçtaki en üstteki bileşeni, yani anası olmayan kökü arar.
lookupPath (?string $type=null, bool $throw=true): ?string
Yol denen şeyi döndürür; bu, geçerli bileşen ile aranan bileşen arasındaki yoldaki tüm bileşenlerin adlarının
birleştirilmesiyle oluşan bir dizedir. Yani örneğin
$component->lookupPath(Nette\Application\UI\Presenter::class), bileşenin presenter'a göre benzersiz
tanımlayıcısını döndürür. $type değeri null olduğunda (ya da atlandığında) yol, ağacın
köküne dek ölçülür.
Container
Nette\ComponentModel\Container,
ana bileşendir; yani çocuk içeren ve böylece ağaç yapısını oluşturan bileşen. Nesneleri kolayca eklemek, almak ve
kaldırmak için metotları vardır. Örneğin formun ya da Control ile Presenter sınıflarının
atasıdır. ArrayAccess trait'ini kullanan alt sınıflar (Control ve Presenter gibi)
çocuklara dizi yazımıyla erişmeye de izin verir, örneğin $container['child'].
addComponent (Component $component, ?string $name, ?string $insertBefore=null): static
Container'a çocuk olarak bir bileşen ekler. $name değeri null ise bileşenin kendi adı
kullanılır. İsteğe bağlı $insertBefore parametresi (var olan bir çocuğun adı) kullanılırsa, yeni bileşen
tam ondan önce eklenir; aksi hâlde sona iliştirilir. Metot container'ın kendisini döndürür, dolayısıyla çağrılar
zincirlenebilir.
removeComponent (Component $component): void
Bir çocuk bileşeni container'dan kaldırır.
getComponent (string $name): ?Component
Bir bileşen döndürür. Tanımlanmamış bir çocuğu almaya çalışmak createComponent($name) factory metodunu
çağırır. createComponent($name) metodu, geçerli bileşende createComponent<bileşen adı>
metodunu, bileşen adını parametre olarak aktararak çağırır. Oluşturulan bileşen sonra geçerli bileşene çocuk olarak
eklenir. Bu metotlara bileşen factory'leri deriz ve onlar Container sınıfından kalıtan sınıflarda
gerçekleştirilebilir.
getComponents(): IComponent[]
Doğrudan alt bileşenleri bir dizi olarak döndürür; anahtarlar bu bileşenlerin adlarını içerir. Alt ağacın tamamını
özyinelemeli almak için, tip süzmesi gerekiyorsa array_filter() ile birleştirerek getComponentTree()
kullanın. (Eski sürümlerden bilinen $deep ve $filterType parametreleri 4.0 sürümünde
kaldırıldı.)
getComponentTree(): list<IComponent>
Tüm iç içe çocuk bileşenler dahil bileşen hiyerarşisinin tamamını indeksli bir dizi olarak alır. Arama derinlik öncelikli yapılır.
Ataları İzleme
Nette bileşen modeli ağaçla çok dinamik çalışmaya izin verir (bileşenleri kaldırabilir, taşıyabilir, ekleyebiliriz), dolayısıyla bir bileşen oluşturulduktan hemen sonra (yapıcıda) anasının, ananın anasının vb. bilindiğine güvenmek yanlış olurdu. Genellikle bileşen oluşturulurken ana hiç bilinmez.
Bir bileşen, bir presenter'ın ya da belirli bir tipteki başka bir atanın altına iliştirildiği anı nasıl öğrenebilir?
Doğrudan anayı izlemek yetmez, çünkü bağlantı ağacın daha yukarısında, örneğin ananın anası iliştirildiğinde
gerçekleşebilir. monitor($type, $attached,
$detached) metodu tam da bunun içindir: bir bileşen, ağaçta üstünde $type sınıfından ya da arayüzünden
bir ata belirdiğinde ya da oradan yittiğinde bildirim almak istediğini bildirir. Bir bileşen istediği kadar tipi izleyebilir;
eşleşen bir ata bağlandığında $attached callback'i tetiklenir ve argüman olarak o atayı alır,
$detached ise ata ayrıldığında tetiklenir. İzleme unmonitor($type) ile yeniden durdurulabilir.
Bildirimler ağaç yapısını izler. İliştirmede bir ata, alt bileşenlerinden önce bildirim alır (yukarıdan aşağıya), böylece bir ana önce paylaşılan durumu hazırlayabilir, hatta bir çocuğu kendi callback'i çalışmadan önce kaldırabilir. Ayırmada sıra terstir; önce alt bileşenler bildirim alır. Callback'ler ayrıca yinelenmeden arındırılır, dolayısıyla aynı callback aynı nesne için asla iki kez çağrılmaz. Bu davranışın ardındaki gerekçe için 4.0 sürümü hakkındaki blog yazısına bakın.
Daha iyi anlamak için bir örnek: Nette Forms'ta dosya yükleme form denetimini temsil eden UploadControl
sınıfı, formun enctype niteliğini multipart/form-data yapmalıdır. Ancak nesnenin oluşturulduğu
anda hiçbir forma iliştirilmemiş olabilir. Öyleyse form hangi noktada değiştirilmelidir? Çözüm basittir: yapıcıda
izleme isteği yapılır:
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');
});
// ...
}
// ...
}
ve form kullanılabilir olur olmaz callback çağrılır.
Daha yeni bir sürüme yükseltiyorsanız yükseltme sayfasına bakın.