Şablon Kalıtımı ve Yeniden Kullanılabilirlik

Şablon yeniden kullanılabilirliği ve kalıtım mekanizmaları üretkenliğinizi artırmak için burada, çünkü her şablon yalnızca benzersiz içerikler içeriyor ve tekrarlanan öğeler ve yapılar yeniden kullanılıyor. Üç 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 sınıf kalıtımına benzer. Diğer çocuk şablonlarının genişletebileceği ve ana şablonun bazı kısımlarını geçersiz kılabileceği bir ana şablon tanımlarsınız. Öğeler ortak bir yapıyı paylaştığında harika çalışır. Kulağa karmaşık mı geliyor? Merak etmeyin, değil.

Düzen Kalıtımı {layout}

Bir örnekle başlayarak düzen şablonu kalıtımına bakalım. Bu, örneğin layout.latte olarak adlandıracağımız bir üst şablon ve bir HTML iskelet belgesini tanımlıyor.

<!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}&copy; Copyright 2008{/block}
	</div>
</body>
</html>

{block} etiketleri, alt şablonların doldurabileceği üç blok tanımlar. Blok etiketinin tek yaptığı, şablon motoruna bir alt şablonun aynı isimde kendi bloğunu tanımlayarak şablonun bu bölümlerini geçersiz kılabileceğini söylemektir.

Bir çocuk şablonu şu şekilde görünebilir:

{layout 'layout.latte'}

{block title}My amazing blog{/block}

{block content}
	<p>Welcome to my awesome homepage.</p>
{/block}

Burada anahtar {layout} etiketidir. Şablon motoruna 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, şablon motoru layout.latte adresindeki üç blok etiketini fark edecek ve bu blokları alt şablonun içeriğiyle değiştirecektir. Alt şablon footer bloğunu tanımlamadığından, bunun yerine üst şablondaki içeriğin kullanıldığını unutmayın. Ana şablondaki bir {block} etiketi içindeki içerik her zaman yedek olarak kullanılır.

Çıktı aşağıdaki gibi 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">
		&copy; Copyright 2008
	</div>
</body>
</html>

Bir alt şablonda, bloklar yalnızca üst seviyede veya başka bir bloğun içinde yer alabilir, örn:

{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şturulacaktır. Düşündüğünüzün aksine, bu şablon bir blok tanımlamaktadır.

{if false}
	{block head}
		<meta name="robots" content="noindex, follow">
	{/block}
{/if}

Blok içindeki çıktının koşullu olarak görüntülenmesini istiyorsanız, bunun yerine aşağıdakileri kullanın:

{block head}
	{if $condition}
		<meta name="robots" content="noindex, follow">
	{/if}
{/block}

Bir alt şablondaki blokların dışındaki veriler, düzen şablonu oluşturulmadan önce yürütülür, böylece {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 Düzeyli Kalıtım

Gerektiği kadar çok sayıda kalıtım düzeyi kullanabilirsiniz. Düzen kalıtımını kullanmanın yaygın bir yolu aşağıdaki üç seviyeli yaklaşımdır:

  1. Sitenizin ana görünümünü ve hissini içeren bir layout.latte şablonu oluşturun.
  2. Sitenizin her bölümü için bir layout-SECTIONNAME.latte şablonu oluşturun. Örneğin, layout-news.latte, layout-blog.latte vb. Bu şablonların tümü layout.latte adresini genişletir ve bölüme özgü stilleri/tasarımı içerir.
  3. Haber makalesi veya blog girişi gibi her sayfa türü için ayrı şablonlar oluşturun. Bu şablonlar uygun bölüm şablonunu genişletir.

Dinamik Yerleşim Kalıtımı

Üst şablonun adı olarak bir değişken veya herhangi bir PHP ifadesi kullanabilirsiniz, 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ı ile çalışmak için bazı ipuçları:

  • Bir şablonda {layout} kullanıyorsanız, bu şablondaki ilk şablon etiketi olmalıdır.
  • Düzen otomatik olarak aranabilir ( sunumlarda olduğu gibi). Bu durumda, şablonun bir düzene sahip olmaması gerekiyorsa, bunu {layout none} etiketi ile belirtecektir.
  • {layout} etiketinin {extends} takma adı vardır.
  • Genişletilmiş şablonun dosya adı şablon yükleyiciye bağlıdır.
  • İstediğiniz kadar bloğa sahip olabilirsiniz. Unutmayın, alt şablonlar tüm üst blokları tanımlamak zorunda değildir, bu nedenle bir dizi blokta makul varsayılanları doldurabilir ve daha sonra yalnızca ihtiyacınız olanları tanımlayabilirsiniz.

Bloklar {block}

Ayrıca bakınız anonim {block}

Bir blok, bir şablonun belirli bir bölümünün nasıl işleneceğini değiştirmenin bir yolunu sağlar, ancak etrafındaki mantığa hiçbir şekilde müdahale etmez. Bir bloğun nasıl çalıştığını ve daha da önemlisi nasıl çalışmadığını göstermek için aşağıdaki örneği ele alalım:

{foreach $posts as $post}
{block post}
	<h1>{$post->title}</h1>
	<p>{$post->body}</p>
{/block}
{/foreach}

Bu şablonu işlerseniz, sonuç blok etiketleri olsun ya da olmasın tamamen aynı olacaktır. Blokların dış kapsamlardaki değişkenlere erişimi vardır. Bu sadece bir alt şablon tarafından geçersiz kılınabilir hale getirmenin bir yoludur:

{layout 'parent.Latte'}

{block post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/block}

Şimdi, alt şablon işlenirken, döngü parent.Latte temel şablonunda tanımlanan blok yerine child.Latte alt şablonunda tanımlanan bloğu kullanacaktır; bu durumda çalıştırılan şablon aşağıdakine eşdeğer olacaktır:

{foreach $posts as $post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/foreach}

Ancak, adlandırılmış bir blok 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 blok içinde görünür olacaktır:

{var $foo = 'foo'}
{block post}
	{do $foo = 'new value'}
	{var $bar = 'bar'}
{/block}

foo: {$foo}                  // prints: foo
bar: {$bar ?? 'not defined'} // prints: not defined

Blok içeriği filtreler tarafından değiştirilebilir. Aşağıdaki örnek, tüm HTML'yi kaldırır ve başlık atar:

<title>{block title|stripHtml|capitalize}...{/block}</title>

Etiket n:attribute şeklinde de yazılabilir:

<article n:block=post>
	...
</article>

Yerel Bloklar

Her blok aynı isimli üst bloğun içeriğini geçersiz kılar. Yerel bloklar hariç. Bunlar sınıftaki özel yöntemler gibi bir şeydir. Blok adlarının çakışması nedeniyle ikinci şablon tarafından üzerlerine yazılacağından endişe etmeden bir şablon oluşturabilirsiniz.

{block local helper}
	...
{/block}

Baskı Blokları {include}

Ayrıca bakınız {include file}

Bir bloğu belirli bir yere yazdırmak için {include blockname} etiketini kullanın:

<title>{block title}{/block}</title>

<h1>{include title}</h1>

Bloğu başka bir şablondan da görüntüleyebilirsiniz:

{include footer from 'main.latte'}

Yazdırılan blok, bloğun dahil edildiği aynı dosyada tanımlanmış olması dışında, etkin bağlamın değişkenlerine erişemez. Ancak global değişkenlere erişimleri vardır.

Değişkenleri bloğa aşağıdaki şekilde aktarabilirsiniz:

{include footer, foo: bar, id: 123}

PHP'de blok adı olarak bir değişken veya herhangi bir ifade kullanabilirsiniz. Bu durumda, değişkenden önce block anahtar sözcüğünü ekleyin, böylece derleme zamanında bunun bir blok olduğu ve adı değişkende de olabilecek şablon eklemediği bilinir:

{var $name = footer}
{include block $name}

Blok kendi içinde de yazdırılabilir, bu da örneğin bir ağaç yapısı oluştururken 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, ...} de yazabiliriz, burada this geçerli blok anlamına gelir.

Yazdırılan içerik filtrelerle değiştirilebilir. Aşağıdaki örnek tüm HTML'yi kaldırır ve başlığını büyük harfle yazar:

<title>{include heading|stripHtml|capitalize}</title>

Ebeveyn Bloğu

Bloğun içeriğini üst şablondan yazdırmanız gerekiyorsa, {include parent} deyimi işinizi görecektir. Bu, bir üst bloğu tamamen geçersiz kılmak yerine içeriğine ekleme yapmak 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. Bunlar normal programlama dillerindeki fonksiyonlarla karşılaştırılabilir. 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 temel olarak tanımlar bloklarla aynıdır ve bloklar hakkında söylenen her şey tanımlar için de geçerlidir. Bloklardan şu açıdan farklıdırlar:

  1. {define} etiketleri içine alınmışlardır
  2. yalnızca şu yolla eklendiklerinde işlenirler {include}
  3. PHP'deki fonksiyonlar gibi bunlar için parametre tanımlayabilirsiniz
{block foo}<p>Hello</p>{/block}
{* prints: <p>Hello</p> *}

{define bar}<p>World</p>{/define}
{* prints nothing *}

{include bar}
{* prints: <p>World</p> *}

HTML formlarının nasıl çizileceğine ilişkin tanımlar içeren bir yardımcı şablonunuz olduğunu düşünün.

{define input, $name, $value, $type = 'text'}
	<input type={$type} name={$name} value={$value}>
{/define}

{define textarea, $name, $value}
	<textarea name={$name}>{$value}</textarea>
{/define}

Bir tanımın argümanları, varsayılan değer belirtilmediği sürece (burada 'text', $type için varsayılan değerdir), varsayılan değer null ile her zaman isteğe bağlıdır. Parametre türleri de bildirilebilir: {define input, string $name, ...}.

Tanımları içeren şablon şu şekilde yüklenir {import}. Tanımların kendileri de bloklarla aynı şekilde oluşturulur:

<p>{include input, 'password', null, 'password'}</p>
<p>{include textarea, 'comment'}</p>

Tanımların aktif bağlamın değişkenlerine erişimi yoktur, ancak global değişkenlere erişimleri vardır.

Dinamik Blok Adları

Latte blokların tanımlanmasında büyük esneklik sağlar çünkü blok adı herhangi bir PHP ifadesi olabilir. Bu örnekte hi-Peter, hi-John ve hi-Mary adında üç blok tanımlanmıştır:

{foreach [Peter, John, Mary] as $name}
	{block "hi-$name"}Hi, I am {$name}.{/block}
{/foreach}

Örneğin, bir alt şablonda yalnızca bir bloğu yeniden tanımlayabiliriz:

{block hi-John}Hello. I am {$name}.{/block}

Böylece çıktı şu şekilde görünecektir:

Hi, I am Peter.
Hello. I am John.
Hi, I am Mary.

Blok Varlığını Kontrol Etme {ifset}

Ayrıca bakınız {ifset $var}

Geçerli bağlamda bir bloğun (veya daha fazla bloğun) var olup olmadığını kontrol etmek için {ifset blockname} testini kullanın:

{ifset footer}
	...
{/ifset}

{ifset footer, header, main}
	...
{/ifset}

PHP'de blok adı olarak bir değişken veya herhangi bir ifade kullanabilirsiniz. Bu durumda, kontrol edilenin değişken olmadığını açıkça belirtmek için değişkenden önce block anahtar sözcüğünü ekleyin:

{ifset block $name}
	...
{/ifset}

Blokların varlığı da fonksiyon tarafından döndürülür hasBlock():

{if hasBlock(header) || hasBlock(footer)}
	...
{/if}

İpuçları

İşte bloklarla çalışmak için bazı ipuçları:

  • Son üst düzey bloğun kapanış etiketine sahip olması gerekmez (blok belgenin sonuyla biter). Bu, bir ana blok olan alt şablonların yazılmasını kolaylaştırır.
  • Daha fazla okunabilirlik için, isteğe bağlı olarak {/block} etiketinize bir ad verebilirsiniz, örneğin {/block footer}. Ancak, ad blok adıyla eşleşmelidir. Daha büyük şablonlarda bu teknik, hangi blok etiketlerinin kapatıldığını görmenize yardımcı olur.
  • Aynı şablonda aynı ada sahip birden fazla blok etiketini doğrudan tanımlayamazsınız. Ancak dinamik blok adları kullanılarak bu sağlanabilir.
  • gibi blokları tanımlamak için n:attributes kullanabilirsiniz <h1 n:block=title>Welcome to my awesome homepage</h1>
  • Bloklar, yalnızca filtreleri çıktıya uygulamak için isimsiz olarak da kullanılabilir: {block|strip} hello {/block}

Yatay Yeniden Kullanım {import}

Yatay yeniden kullanım, Latte'de yeniden kullanım ve kalıtım için üçüncü mekanizmadır. Diğer şablonlardan blokların yüklenmesine izin verir. PHP'de yardımcı işlevlerle bir dosya oluşturmaya ve ardından require kullanarak 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 bir başka şablonu genişletebilir. Yatay yeniden kullanım, çoklu kalıtım elde etmenin bir yoludur.

Bir dizi blok tanımına sahip olalım:

{block sidebar}...{/block}

{block menu}...{/block}

{import} komutunu kullanarak, blocks.latte adresinde tanımlanan tüm blokları ve tanımları başka bir şablona aktarın:

{import 'blocks.latte'}

{* sidebar ve menü blokları artık kullanılabilir *}

Ana şablondaki blokları içe aktarırsanız (yani {import} adresini layout.latte adresinde kullanırsanız), bloklar tüm alt şablonlarda da kullanılabilir olacaktır, bu da çok kullanışlıdır.

İçe aktarılması amaçlanan ş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} adresinden sonraki ilk şablon etiketi olmalıdır. Şablon adı herhangi bir PHP ifadesi olabilir:

{import $ajax ? 'ajax.latte' : 'not-ajax.latte'}

Herhangi bir şablonda istediğiniz kadar {import} ifadesi kullanabilirsiniz. İki içe aktarılan şablon aynı bloğu tanımlarsa, ilki kazanır. Ancak, en yüksek öncelik, içe aktarılan herhangi bir bloğun üzerine yazabilen ana şablona verilir.

Üzerine yazılan blokların içeriği, blok bir üst blokla aynı şekilde eklenerek 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 doğru şekilde çağıracaktır.

Birim Kalıtımı {embed}

Birim kalıtımı, düzen kalıtımı fikrini içerik parçaları düzeyine taşır. Düzen kalıtımı, alt şablonlar tarafından hayata geçirilen “belge iskeletleri” 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 {embed} etiketi anahtardır. {include} ve {layout} etiketlerinin davranışlarını birleştirir. {include} etiketinde olduğu gibi, başka bir şablonun veya bloğun içeriğini dahil etmenize ve isteğe bağlı olarak değişkenleri aktarmanıza olanak tanır. Ayrıca, {layout} 'un yaptığı gibi, dahil edilen şablonun içinde tanımlanan herhangi bir bloğu geçersiz kılmanıza da olanak tanır.

Örneğin biz katlanabilir akordeon elemanını kullanacağız. collapsible.latte şablonundaki eleman iskeletine bir göz atalı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 şablonundaki ana şablonda olduğu gibi. Ayrıca $modifierClass değişkenini de görüyorsunuz.

Elemanımızı şablon içinde kullanalım. İşte burada {embed} devreye giriyor. Her şeyi yapmamıza izin veren süper güçlü bir kit parçasıdır: öğenin şablon içeriğini dahil edin, ona değişkenler ekleyin ve ona özel HTML içeren bloklar ekleyin:

{embed 'collapsible.latte', modifierClass: my-style}
	{block title}
		Hello World
	{/block}

	{block content}
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
		elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
	{/block}
{/embed}

Çıktı aşağıdaki gibi görünebilir:

<section class="collapsible my-style">
	<h4 class="collapsible__title">
		Hello World
	</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ömme etiketlerinin içindeki bloklar diğer bloklardan bağımsız ayrı bir katman oluşturur. Bu nedenle, gömme dışındaki blokla aynı ada sahip olabilirler ve hiçbir şekilde etkilenmezler. {embed} etiketleri içindeki include etiketini kullanarak burada oluşturulan blokları, gömülü şablondan ( yerel olmayan) blokları ve ayrıca ana şablondan [yerel |#Local Blocks] olan blokları ekleyebilirsiniz. Blokları başka dosyalardan da 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 gömme içinde tanımlanır *}
		{include hello} {* çalışır, blok bu şablonda yereldir *}
		{include content} {* çalışır, blok gömülü şablonda tanımlanmıştır *}
		{include aBlockDefinedInImportedTemplate} {* çalışır *}
		{include outer} {* çalışmıyor! - blok dış katmanda *}
	{/block}
{/embed}

Gömülü şablonların etkin bağlamın değişkenlerine erişimi yoktur, ancak küresel değişkenlere erişimleri vardır.

{embed} ile sadece şablonları değil diğer blokları da ekleyebilirsiniz, 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}
		Hello World
	{/block}
	...
{/embed}

{embed} adresine bir ifade iletirsek ve bunun bir blok mu yoksa dosya adı mı olduğu net değilse, block veya file anahtar sözcüğünü ekleyin:

{embed block $name} ... {/embed}

Kullanım Örnekleri

Latte'de çeşitli kalıtım ve kod yeniden kullanımı türleri vardır. Daha fazla açıklık için ana kavramları özetleyelim:

{include template}

Kullanım Örneği: layout.latte içinde header.latte & footer.latte kullanılması.

header.latte

<nav>
   <div>Home</div>
   <div>About</div>
</nav>

footer.latte

<footer>
   <div>Copyright</div>
</footer>

layout.latte

{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}

{layout}

Kullanım Örneği: layout.latte 'u homepage.latte & about.latte içinde genişletme.

layout.latte

{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}

homepage.latte

{layout 'layout.latte'}

{block main}
	<p>Homepage</p>
{/block}

about.latte

{layout 'layout.latte'}

{block main}
	<p>About page</p>
{/block}

{import}

Kullanım Örneği: sidebar.latte içinde single.product.latte & single.service.latte.

sidebar.latte

{block sidebar}<aside>This is sidebar</aside>{/block}

single.product.latte

{layout 'product.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Product page</main>{/block}

single.service.latte

{layout 'service.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Service page</main>{/block}

{define}

Kullanım Örneği: Bazı değişkenleri alan ve bazı biçimlendirmeleri çıktı olarak veren bir işlev.

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, Submit, submit}</div>
</form>

{embed}

Kullanım Örneği: pagination.latte adresini product.table.latte & service.table.latte adreslerine 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}First Product Page{/block}
	{block last}Last Product Page{/block}
{/embed}

service.table.latte

{embed 'pagination.latte', min: 1, max: $services->count}
	{block first}First Service Page{/block}
	{block last}Last Service Page{/block}
{/embed}
versiyon: 3.0