Şablon Kalıtımı ve Yeniden Kullanılabilirliği
Şablon yeniden kullanım ve kalıtım mekanizmaları verimliliğinizi artıracaktır, çünkü her şablon yalnızca benzersiz içeriğini içerir ve tekrarlanan öğeler ve yapılar yeniden kullanılır. Üç kavramı tanıtıyoruz: Düzen Kalıtımı, Yatay Yeniden Kullanım ve Birim Kalıtımı.
Latte şablon kalıtımı kavramı, PHP'deki sınıf kalıtımına benzer. Diğer alt şablonların miras alabileceği ve üst şablonun bölümlerini geçersiz kılabileceği bir üst şablon tanımlarsınız. Öğeler ortak bir yapıyı paylaştığında harika çalışır. Kulağa karmaşık mı geliyor? Endişelenmeyin, çok kolay.
Düzen Kalıtımı {layout}
Düzen şablonu kalıtımına, yani düzene bir örnekle bakalım. Bu, örneğin layout.latte
olarak
adlandıracağımız ve bir HTML belgesinin iskeletini tanımlayan üst şablondur:
<!doctype html>
<html lang="en">
<head>
<title>{block title}{/block}</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="content">
{block content}{/block}
</div>
<div id="footer">
{block footer}© Copyright 2008{/block}
</div>
</body>
</html>
{block}
etiketleri, alt şablonların doldurabileceği üç blok tanımlar. block
etiketi yalnızca,
alt şablonun aynı ada sahip kendi bloğunu tanımlayarak bu yeri geçersiz kılabileceğini bildirir.
Bir alt şablon şöyle görünebilir:
{layout 'layout.latte'}
{block title}My amazing blog{/block}
{block content}
<p>Welcome to my awesome homepage.</p>
{/block}
Buradaki anahtar {layout}
etiketidir. Latte'ye bu şablonun başka bir şablonu „genişlettiğini“ söyler.
Latte bu şablonu işlediğinde, önce üst şablonu bulur – bu durumda layout.latte
.
Bu noktada Latte, layout.latte
içindeki üç blok etiketini fark eder ve bu blokları alt şablonun içeriğiyle
değiştirir. Alt şablon footer bloğunu tanımlamadığı için, bunun yerine üst şablondaki içerik kullanılır. Üst
şablondaki {block}
etiketindeki içerik her zaman yedek olarak kullanılır.
Çıktı şöyle görünebilir:
<!doctype html>
<html lang="en">
<head>
<title>My amazing blog</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="content">
<p>Welcome to my awesome homepage.</p>
</div>
<div id="footer">
© Copyright 2008
</div>
</body>
</html>
Alt şablonda, bloklar yalnızca en üst düzeyde veya başka bir bloğun içinde yerleştirilebilir, yani:
{block content}
<h1>{block title}Welcome to my awesome homepage{/block}</h1>
{/block}
Ayrıca, çevreleyen {if}
koşulunun doğru veya yanlış olarak değerlendirilip değerlendirilmediğine
bakılmaksızın her zaman bir blok oluşturulur. Yani öyle görünmese bile, bu şablon bloğu tanımlar.
{if false}
{block head}
<meta name="robots" content="noindex, follow">
{/block}
{/if}
Bloğun içindeki çıktının koşullu olarak görüntülenmesini istiyorsanız, bunun yerine aşağıdakini kullanın:
{block head}
{if $condition}
<meta name="robots" content="noindex, follow">
{/if}
{/block}
Alt şablondaki blokların dışındaki alan, düzen şablonu işlenmeden önce yürütülür, böylece bunları
{var $foo = bar}
gibi değişkenleri tanımlamak ve verileri tüm kalıtım zincirine yaymak için
kullanabilirsiniz:
{layout 'layout.latte'}
{var $robots = noindex}
...
Çok Seviyeli Kalıtım
İhtiyaç duyduğunuz kadar çok kalıtım seviyesi kullanabilirsiniz. Düzen kalıtımını kullanmanın yaygın bir yolu aşağıdaki üç seviyeli yaklaşımdır:
- Sitenizin ana görünüm iskeletini içeren bir
layout.latte
şablonu oluşturun. - Sitenizin her bölümü için bir
layout-SECTIONNAME.latte
şablonu oluşturun. Örneğin,layout-news.latte
,layout-blog.latte
vb. Tüm bu şablonlarlayout.latte
'yi genişletir ve her bölüme özgü stilleri ve tasarımı içerir. - Her sayfa türü için ayrı şablonlar oluşturun, örneğin bir haber makalesi veya bir blog gönderisi. Bu şablonlar ilgili bölüm şablonunu genişletir.
Dinamik Kalıtım
Üst şablonun adı olarak bir değişken veya herhangi bir PHP ifadesi kullanılabilir, böylece kalıtım dinamik olarak davranabilir:
{layout $standalone ? 'minimum.latte' : 'layout.latte'}
Düzen şablonunu otomatik olarak seçmek için Latte API'sini de kullanabilirsiniz.
İpuçları
Düzen kalıtımıyla çalışmak için bazı ipuçları:
- Bir şablonda
{layout}
kullanırsanız, bu şablondaki ilk şablon etiketi olmalıdır. - Düzen otomatik olarak bulunabilir
(örneğin Presenter'larda olduğu gibi). Bu
durumda, şablonun bir düzeni olmaması gerekiyorsa, bunu
{layout none}
etiketiyle bildirir. {layout}
etiketinin bir takma adı vardır:{extends}
.- Düzen dosyasının adı yükleyiciye bağlıdır.
- İstediğiniz kadar blok sahibi olabilirsiniz. Unutmayın, alt şablonların tüm üst blokları tanımlaması gerekmez, bu nedenle birkaç blokta makul varsayılan değerler doldurabilir ve ardından yalnızca daha sonra ihtiyacınız olanları tanımlayabilirsiniz.
Bloklar {block}
Ayrıca bkz. anonim {block}
Bir blok, bir şablonun belirli bir bölümünün nasıl işleneceğini değiştirmenin bir yoludur, ancak etrafındaki mantığa müdahale etmez. Aşağıdaki örnekte, bir bloğun nasıl çalıştığını ve ayrıca nasıl çalışmadığını göstereceğiz:
{foreach $posts as $post}
{block post}
<h1>{$post->title}</h1>
<p>{$post->body}</p>
{/block}
{/foreach}
Bu şablonu işlerseniz, sonuç {block}
etiketleriyle veya etiketleri olmadan tamamen aynı olacaktır. Bloklar,
dış kapsamlardaki değişkenlere erişebilir. Sadece bir alt şablon tarafından geçersiz kılınma olasılığını
verirler:
{layout 'parent.Latte'}
{block post}
<article>
<header>{$post->title}</header>
<section>{$post->text}</section>
</article>
{/block}
Şimdi, alt şablonu işlerken, döngü parent.Latte
'de tanımlanan blok yerine child.Latte
alt
şablonunda tanımlanan bloğu kullanacaktır; çalıştırılan şablon daha sonra aşağıdakine eşdeğerdir:
{foreach $posts as $post}
<article>
<header>{$post->title}</header>
<section>{$post->text}</section>
</article>
{/foreach}
Ancak, adlandırılmış bir bloğun içinde yeni bir değişken oluşturursak veya mevcut bir değişkenin değerini değiştirirsek, değişiklik yalnızca bloğun içinde görünür olacaktır:
{var $foo = 'foo'}
{block post}
{do $foo = 'new value'}
{var $bar = 'bar'}
{/block}
foo: {$foo} // yazdırır: foo
bar: {$bar ?? 'not defined'} // yazdırır: not defined
Bloğun içeriği filtreler kullanılarak değiştirilebilir. Aşağıdaki örnek tüm HTML'yi kaldırır ve harf boyutunu değiştirir:
<title>{block title|stripHtml|capitalize}...{/block}</title>
Etiket ayrıca n:niteliği olarak da yazılabilir:
<article n:block=post>
...
</article>
Yerel Bloklar
Her blok, aynı ada sahip üst bloğun içeriğini geçersiz kılar – yerel bloklar hariç. Sınıflarda, bu özel metotlar gibi bir şey olurdu. Böylece, blok adlarının çakışması nedeniyle başka bir şablondan geçersiz kılınacağından endişe etmeden şablonu oluşturabilirsiniz.
{block local helper}
...
{/block}
Blokları İşleme {include}
Ayrıca bkz. {include file}
Belirli bir yerde bir blok yazdırmak için {include blockname}
etiketini kullanın:
<title>{block title}{/block}</title>
<h1>{include title}</h1>
Başka bir şablondan bir blok da yazdırılabilir:
{include footer from 'main.latte'}
İşlenen blok, bloğun dahil edildiği aynı dosyada tanımlanmadığı sürece etkin bağlamın değişkenlerine erişemez. Ancak, genel değişkenlere erişebilir.
Değişkenleri bloğa şu şekilde iletebilirsiniz:
{include footer, foo: bar, id: 123}
Blok adı olarak bir değişken veya herhangi bir PHP ifadesi kullanılabilir. Bu durumda, değişkenin önüne
block
anahtar kelimesini ekleriz, böylece Latte derleme zamanında bunun bir blok olduğunu ve adı da bir
değişkende olabilecek şablon dahil etme olmadığını bilir:
{var $name = footer}
{include block $name}
Blok kendi içinde de işlenebilir, bu örneğin bir ağaç yapısını işlerken kullanışlıdır:
{define menu, $items}
<ul>
{foreach $items as $item}
<li>
{if is_array($item)}
{include menu, $item}
{else}
{$item}
{/if}
</li>
{/foreach}
</ul>
{/define}
{include menu, ...}
yerine {include this, ...}
yazabiliriz, burada this
geçerli blok
anlamına gelir.
İşlenen blok filtreler kullanılarak değiştirilebilir. Aşağıdaki örnek tüm HTML'yi kaldırır ve harf boyutunu değiştirir:
<title>{include heading|stripHtml|capitalize}</title>
Üst Blok
Üst şablondan bir bloğun içeriğini yazdırmanız gerekiyorsa, {include parent}
kullanın. Bu, üst bloğun
içeriğini tamamen geçersiz kılmak yerine yalnızca tamamlamak istediğinizde kullanışlıdır.
{block footer}
{include parent}
<a href="https://github.com/nette">GitHub</a>
<a href="https://twitter.com/nettefw">Twitter</a>
{/block}
Tanımlar {define}
Bloklara ek olarak, Latte'de “tanımlar” da vardır. Yaygın programlama dillerinde, bunları fonksiyonlarla karşılaştırırdık. Kendinizi tekrar etmemek için şablon parçalarını yeniden kullanmak için kullanışlıdırlar.
Latte işleri basit tutmaya çalışır, bu nedenle temelde tanımlar bloklarla aynıdır ve bloklar hakkında söylenen her şey tanımlar için de geçerlidir. Bloklardan şu şekilde farklıdırlar:
{define}
etiketleri içine alınırlar- Yalnızca
{include}
aracılığıyla dahil edildiklerinde işlenirler - PHP'deki fonksiyonlara benzer şekilde parametreler tanımlanabilir
{block foo}<p>Merhaba</p>{/block}
{* yazdırır: <p>Merhaba</p> *}
{define bar}<p>Dünya</p>{/define}
{* hiçbir şey yazdırmaz *}
{include bar}
{* yazdırır: <p>Dünya</p> *}
HTML formlarının nasıl çizileceğine dair bir tanım koleksiyonu içeren bir yardımcı şablonunuz olduğunu hayal edin.
{define input, $name, $value, $type = 'text'}
<input type={$type} name={$name} value={$value}>
{/define}
{define textarea, $name, $value}
<textarea name={$name}>{$value}</textarea>
{/define}
Argümanlar her zaman isteğe bağlıdır ve varsayılan bir değer belirtilmezse varsayılan değer null
olur
(burada 'text'
, $type
için varsayılan değerdir). Parametre tipleri de bildirilebilir:
{define input, string $name, ...}
.
Tanımları içeren şablonu {import}
kullanarak yükleriz.
Tanımların kendileri bloklarla aynı şekilde işlenir:
<p>{include input, 'password', null, 'password'}</p>
<p>{include textarea, 'comment'}</p>
Tanımlar, etkin bağlamın değişkenlerine erişemez, ancak genel değişkenlere erişebilir.
Dinamik Blok Adları
Latte, blokları tanımlarken büyük esneklik sağlar, çünkü blok adı herhangi bir PHP ifadesi olabilir. Bu örnek,
hi-Peter
, hi-John
ve hi-Mary
adlarıyla üç blok tanımlar:
{foreach [Peter, John, Mary] as $name}
{block "hi-$name"}Hi, I am {$name}.{/block}
{/foreach}
Alt şablonda, örneğin yalnızca bir bloğu yeniden tanımlayabiliriz:
{block hi-John}Hello. I am {$name}.{/block}
Böylece çıktı şöyle görünecektir:
Hi, I am Peter.
Hello. I am John.
Hi, I am Mary.
Blok Varlığını Kontrol Etme {ifset}
Ayrıca bkz. {ifset $var}
{ifset blockname}
testini kullanarak, geçerli bağlamda bir bloğun (veya birden çok bloğun) var olup
olmadığını kontrol ederiz:
{ifset footer}
...
{/ifset}
{ifset footer, header, main}
...
{/ifset}
Blok adı olarak bir değişken veya herhangi bir PHP ifadesi kullanılabilir. Bu durumda, değişkenin önüne
block
anahtar kelimesini ekleriz, böylece bunun değişkenlerin varlığını test etmek olmadığını açıkça
belirtiriz:
{ifset block $name}
...
{/ifset}
Blokların varlığı ayrıca hasBlock()
fonksiyonu tarafından da doğrulanır:
{if hasBlock(header) || hasBlock(footer)}
...
{/if}
İpuçları
Bloklarla çalışmak için birkaç ipucu:
- Son en üst düzey bloğun bir kapanış etiketi olması gerekmez (blok belgenin sonunda biter). Bu, tek bir birincil blok içeren alt şablonların yazılmasını basitleştirir.
- Daha iyi okunabilirlik için, blok adını
{/block}
etiketinde belirtebilirsiniz, örneğin{/block footer}
. Ancak, ad blok adıyla eşleşmelidir. Daha büyük şablonlarda, bu teknik hangi blok etiketlerinin kapandığını görmenize yardımcı olur. - Aynı şablonda aynı ada sahip birden çok blok etiketini doğrudan tanımlayamazsınız. Ancak, bu dinamik blok adları kullanılarak başarılabilir.
- Blokları tanımlamak için n:nitelikleri kullanabilirsiniz,
örneğin
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Bloklar ayrıca yalnızca filtreleri kullanmak için adsız olarak
da kullanılabilir:
{block|strip} hello {/block}
Yatay Yeniden Kullanım {import}
Yatay yeniden kullanım, Latte'deki yeniden kullanım ve kalıtım için üçüncü mekanizmadır. Diğer şablonlardan
blokları yüklemenizi sağlar. Bu, PHP'de yardımcı fonksiyonlar içeren bir dosya oluşturup ardından require
ile
yüklemeye benzer.
Şablon düzeni kalıtımı Latte'nin en güçlü özelliklerinden biri olsa da, basit kalıtımla sınırlıdır – bir şablon yalnızca başka bir şablonu genişletebilir. Yatay yeniden kullanım, çoklu kalıtım elde etmenin bir yoludur.
Blok tanımları içeren bir dosyamız olsun:
{block sidebar}...{/block}
{block menu}...{/block}
{import}
komutunu kullanarak, blocks.latte
'de tanımlanan tüm blokları ve Tanımlar başka bir şablona aktarırız:
{import 'blocks.latte'}
{* şimdi sidebar ve menu blokları kullanılabilir *}
Blokları üst şablonda içe aktarırsanız (yani {import}
'u layout.latte
'de kullanırsanız),
bloklar tüm alt şablonlarda da kullanılabilir olacaktır, bu çok pratiktir.
İçe aktarılacak şablon (örneğin blocks.latte
), başka bir şablonu genişletmemelidir, yani {layout}
kullanmamalıdır. Ancak, diğer şablonları
içe aktarabilir.
{import}
etiketi, {layout}
'tan sonraki ilk şablon etiketi olmalıdır. Şablon adı herhangi bir PHP
ifadesi olabilir:
{import $ajax ? 'ajax.latte' : 'not-ajax.latte'}
Bir şablonda istediğiniz kadar {import}
komutu kullanabilirsiniz. İki içe aktarılan şablon aynı bloğu
tanımlarsa, ilki kazanır. Ancak, en yüksek öncelik ana şablondadır ve herhangi bir içe aktarılan bloğu geçersiz
kılabilir.
Geçersiz kılınan blokların içeriği, bloğu üst blok dahil edildiği gibi dahil ederek korunabilir:
{layout 'layout.latte'}
{import 'blocks.latte'}
{block sidebar}
{include parent}
{/block}
{block title}...{/block}
{block content}...{/block}
Bu örnekte, {include parent}
, blocks.latte
şablonundan sidebar
bloğunu
çağırır.
Birim Kalıtımı {embed}
Birim kalıtımı, düzen kalıtımı fikrini içerik parçaları düzeyine genişletir. Düzen kalıtımı, alt şablonlar tarafından canlandırılan “belge iskeleti” ile çalışırken, birim kalıtımı daha küçük içerik birimleri için iskeletler oluşturmanıza ve bunları istediğiniz yerde yeniden kullanmanıza olanak tanır.
Birim kalıtımında anahtar {embed}
etiketidir. {include}
ve {layout}
davranışlarını birleştirir. Başka bir şablonun veya bloğun içeriğini gömmenize ve isteğe bağlı olarak değişkenleri
iletmenize olanak tanır, tıpkı {include}
durumunda olduğu gibi. Ayrıca, {layout}
kullanırken
olduğu gibi, gömülü şablon içinde tanımlanan herhangi bir bloğu geçersiz kılmanıza da olanak tanır.
Örneğin, bir akordeon öğesi kullanacağız. collapsible.latte
şablonunda saklanan öğenin iskeletine
bakalım:
<section class="collapsible {$modifierClass}">
<h4 class="collapsible__title">
{block title}{/block}
</h4>
<div class="collapsible__content">
{block content}{/block}
</div>
</section>
{block}
etiketleri, alt şablonların doldurabileceği iki blok tanımlar. Evet, düzen kalıtımındaki üst
şablon durumunda olduğu gibi. Ayrıca $modifierClass
değişkenini de görüyorsunuz.
Öğemizi bir şablonda kullanalım. İşte burada {embed}
devreye giriyor. Bu, bize her şeyi yapmamızı
sağlayan son derece güçlü bir etikettir: öğe şablonunun içeriğini gömmek, ona değişkenler eklemek ve ona kendi
HTML'mizle bloklar eklemek:
{embed 'collapsible.latte', modifierClass: my-style}
{block title}
Merhaba Dünya
{/block}
{block content}
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
{/block}
{/embed}
Çıktı şöyle görünebilir:
<section class="collapsible my-style">
<h4 class="collapsible__title">
Merhaba Dünya
</h4>
<div class="collapsible__content">
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
</div>
</section>
Gömülü etiketlerin içindeki bloklar, diğer bloklardan bağımsız ayrı bir katman oluşturur. Bu nedenle, gömme
dışındaki bir blokla aynı ada sahip olabilirler ve hiçbir şekilde etkilenmezler. {embed}
etiketlerinin içinde
include etiketini kullanarak, burada oluşturulan blokları, gömülü şablondaki blokları
(değil yerel) ve ayrıca ana şablondaki olan yerel blokları dahil edebilirsiniz.
Ayrıca diğer dosyalardan blokları içe aktarabilirsiniz:
{block outer}…{/block}
{block local hello}…{/block}
{embed 'collapsible.latte', modifierClass: my-style}
{import 'blocks.latte'}
{block inner}…{/block}
{block title}
{include inner} {* çalışır, blok embed içinde tanımlandı *}
{include hello} {* çalışır, blok bu şablonda yerel *}
{include content} {* çalışır, blok gömülü şablonda tanımlandı *}
{include aBlockDefinedInImportedTemplate} {* çalışır *}
{include outer} {* çalışmaz! - blok dış katmanda *}
{/block}
{/embed}
Gömülü şablonlar, etkin bağlamın değişkenlerine erişemez, ancak genel değişkenlere erişebilir.
{embed}
kullanarak yalnızca şablonları değil, diğer blokları da gömebiliriz ve bu nedenle önceki örnek
şu şekilde yazılabilir:
{define collapsible}
<section class="collapsible {$modifierClass}">
<h4 class="collapsible__title">
{block title}{/block}
</h4>
...
</section>
{/define}
{embed collapsible, modifierClass: my-style}
{block title}
Merhaba Dünya
{/block}
...
{/embed}
{embed}
'e bir ifade iletirsek ve bunun bir blok adı mı yoksa dosya adı mı olduğu açık değilse,
block
veya file
anahtar kelimesini ekleriz:
{embed block $name} ... {/embed}
Kullanım Durumları
Latte'de farklı kalıtım ve kod yeniden kullanım türleri vardır. Daha fazla netlik için ana kavramları özetleyelim:
{include template}
Kullanım durumu: layout.latte
içinde header.latte
ve footer.latte
kullanma.
header.latte
<nav>
<div>Ana Sayfa</div>
<div>Hakkında</div>
</nav>
footer.latte
<footer>
<div>Telif Hakkı</div>
</footer>
layout.latte
{include 'header.latte'}
<main>{block main}{/block}</main>
{include 'footer.latte'}
{layout}
Kullanım durumu: homepage.latte
ve about.latte
içinde layout.latte
'yi
genişletme.
layout.latte
{include 'header.latte'}
<main>{block main}{/block}</main>
{include 'footer.latte'}
homepage.latte
{layout 'layout.latte'}
{block main}
<p>Ana Sayfa</p>
{/block}
about.latte
{layout 'layout.latte'}
{block main}
<p>Hakkında Sayfası</p>
{/block}
{import}
Kullanım durumu: single.product.latte
ve single.service.latte
içinde
sidebar.latte
.
sidebar.latte
{block sidebar}<aside>Burası kenar çubuğu</aside>{/block}
single.product.latte
{layout 'product.layout.latte'}
{import 'sidebar.latte'}
{block main}<main>Ürün sayfası</main>{/block}
single.service.latte
{layout 'service.layout.latte'}
{import 'sidebar.latte'}
{block main}<main>Hizmet sayfası</main>{/block}
{define}
Kullanım durumu: Değişkenleri ilettiğimiz ve bir şeyler işleyen fonksiyonlar.
form.latte
{define form-input, $name, $value, $type = 'text'}
<input type={$type} name={$name} value={$value}>
{/define}
profile.service.latte
{import 'form.latte'}
<form action="" method="post">
<div>{include form-input, username}</div>
<div>{include form-input, password}</div>
<div>{include form-input, submit, Gönder, submit}</div>
</form>
{embed}
Kullanım durumu: product.table.latte
ve service.table.latte
içine
pagination.latte
gömme.
pagination.latte
<div id="pagination">
<div>{block first}{/block}</div>
{for $i = $min + 1; $i < $max - 1; $i++}
<div>{$i}</div>
{/for}
<div>{block last}{/block}</div>
</div>
product.table.latte
{embed 'pagination.latte', min: 1, max: $products->count}
{block first}İlk Ürün Sayfası{/block}
{block last}Son Ürün Sayfası{/block}
{/embed}
service.table.latte
{embed 'pagination.latte', min: 1, max: $services->count}
{block first}İlk Hizmet Sayfası{/block}
{block last}Son Hizmet Sayfası{/block}
{/embed}