Dedovanje predlog in ponovna uporabnost
Mehanizmi ponovne uporabnosti in dedovanja predlog povečujejo vašo produktivnost, saj vsaka predloga vsebuje le svojo edinstveno vsebino, ponavljajoči se elementi in strukture pa so ponovno uporabljeni. Predstavljamo tri koncepte: dedovanje postavitve, horizontalno ponovno uporabo in dedovanje enot.
Koncept dedovanja predlog Latte je podoben dedovanju razredov PHP. Določite starševsko predlogo, ki jo lahko druge družinske predloge razširijo in prekrijejo dele starševske predloge. To se odlično obnese, kadar si elementi delijo skupno strukturo. Se vam zdi zapleteno? Brez skrbi, ni.
Dedovanje postavitve {layout}
Oglejmo si dedovanje predlog postavitve s primerom. To je nadrejena predloga, ki jo bomo na primer poimenovali
layout.latte
in opredeljuje skeletni dokument HTML.
<!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>
Oznake {block}
opredeljujejo tri bloke, ki jih lahko zapolnijo podrejene predloge. Vse, kar naredi oznaka bloka,
je, da pove gonilniku predloge, da lahko podrejena predloga prekrije te dele predloge z opredelitvijo lastnega bloka z istim
imenom.
Otroška predloga je lahko videti takole:
{layout 'layout.latte'}
{block title}My amazing blog{/block}
{block content}
<p>Welcome to my awesome homepage.</p>
{/block}
Pri tem je ključna oznaka {layout}
. Ta sporoča mehanizmu predlog, da ta predloga “razširja” drugo predlogo.
Ko Latte upodablja to predlogo, najprej poišče nadrejeno – v tem primeru layout.latte
.
Takrat bo mehanizem predloge opazil tri blokovne oznake v layout.latte
in te bloke nadomestil z vsebino podrejene
predloge. Upoštevajte, da ker otroška predloga ni opredelila bloka footer, se namesto tega uporabi vsebina iz starševske
predloge. Vsebina znotraj oznake {block}
v nadrejeni predlogi se vedno uporabi kot nadomestna možnost.
Rezultat je lahko videti takole:
<!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>
V predlogi otroka se bloki lahko nahajajo samo na zgornji ravni ali znotraj drugega bloka, tj:
{block content}
<h1>{block title}Welcome to my awesome homepage{/block}</h1>
{/block}
Prav tako bo blok vedno ustvarjen ne glede na to, ali je okoliški pogoj {if}
ovrednoten kot true ali false.
V nasprotju s tem, kar morda mislite, ta predloga opredeljuje blok.
{if false}
{block head}
<meta name="robots" content="noindex, follow">
{/block}
{/if}
Če želite, da se izpis znotraj bloka prikaže pogojno, namesto tega uporabite naslednje:
{block head}
{if $condition}
<meta name="robots" content="noindex, follow">
{/if}
{/block}
Podatki zunaj blokov v podrejeni predlogi se izvedejo pred prikazom predloge za postavitev, zato jo lahko uporabite za
opredelitev spremenljivk, kot je {var $foo = bar}
, in širjenje podatkov v celotno dedno verigo:
{layout 'layout.latte'}
{var $robots = noindex}
...
Večnivojsko dedovanje
Uporabite lahko toliko ravni dedovanja, kolikor jih potrebujete. Eden od pogostih načinov uporabe dedovanja postavitve je naslednji tristopenjski pristop:
- Ustvarite predlogo
layout.latte
, ki vsebuje glavni videz vašega spletnega mesta. - Ustvarite predlogo
layout-SECTIONNAME.latte
za vsak razdelek svojega spletnega mesta. Na primerlayout-news.latte
,layout-blog.latte
itd. Vse te predloge razširjajo spletno stranlayout.latte
in vključujejo sloge/oblikovanje, značilne za posamezno poglavje. - Ustvarite posamezne predloge za vsako vrsto strani, na primer za novičarski članek ali zapis na blogu. Te predloge razširjajo ustrezno predlogo za razdelek.
Dinamično dedovanje postavitve
Kot ime nadrejene predloge lahko uporabite spremenljivko ali kateri koli izraz PHP, zato se lahko dedovanje obnaša dinamično:
{layout $standalone ? 'minimum.latte' : 'layout.latte'}
Uporabite lahko tudi API Latte za samodejno izbiro predloge za postavitev.
Nasveti
Tukaj je nekaj nasvetov za delo z dedovanjem postavitve:
- Če v predlogi uporabite
{layout}
, mora biti to prva oznaka v predlogi. - Postavitev lahko iščete samodejno (kot v predstavitvah). Če v tem primeru predloga ne sme
imeti postavitve, se to označi z oznako
{layout none}
. - Oznaka
{layout}
ima vzdevek{extends}
. - Ime datoteke razširjene predloge je odvisno od programa za nalaganje predlog.
- Na voljo je lahko poljubno število blokov. Ne pozabite, da podrejenim predlogam ni treba opredeliti vseh nadrejenih blokov, zato lahko v več blokov vnesete razumne privzete nastavitve, pozneje pa opredelite le tiste, ki jih potrebujete.
Bloki {block}
Glej tudi anonimni {block}
Blok omogoča spreminjanje načina upodabljanja določenega dela predloge, vendar na noben način ne posega v okoliško logiko. Z naslednjim primerom ponazorimo, kako blok deluje in, kar je še pomembneje, kako ne deluje:
{foreach $posts as $post}
{block post}
<h1>{$post->title}</h1>
<p>{$post->body}</p>
{/block}
{/foreach}
Če to predlogo prikažete, bo rezultat popolnoma enak z oznakami bloka ali brez njih. Bloki imajo dostop do spremenljivk iz zunanjih obsegov. To je le način, da ga lahko podrejena predloga prekrije:
{layout 'parent.Latte'}
{block post}
<article>
<header>{$post->title}</header>
<section>{$post->text}</section>
</article>
{/block}
Sedaj bo zanka pri upodabljanju podrejene predloge uporabila blok, opredeljen v podrejeni predlogi child.Latte
,
namesto bloka, opredeljenega v osnovni predlogi parent.Latte
; izvedena predloga je nato enakovredna naslednji:
{foreach $posts as $post}
<article>
<header>{$post->title}</header>
<section>{$post->text}</section>
</article>
{/foreach}
Če pa znotraj poimenovanega bloka ustvarimo novo spremenljivko ali zamenjamo vrednost obstoječe, bo sprememba vidna samo znotraj bloka:
{var $foo = 'foo'}
{block post}
{do $foo = 'new value'}
{var $bar = 'bar'}
{/block}
foo: {$foo} // prints: foo
bar: {$bar ?? 'not defined'} // prints: not defined
Vsebino bloka lahko spremenimo s filtri. Naslednji primer odstrani ves HTML in ga naslovi:
<title>{block title|stripHtml|capitalize}...{/block}</title>
Oznaka je lahko zapisana tudi kot n:attribute:
<article n:block=post>
...
</article>
Lokalni bloki
Vsak blok prekrije vsebino nadrejenega bloka z istim imenom. Razen lokalnih blokov. Ti so nekaj podobnega kot zasebne metode v razredu. Ustvarite lahko predlogo, ne da bi vas skrbelo, da bi jih – zaradi naključja imen blokov – druga predloga prepisala.
{block local helper}
...
{/block}
Tiskanje blokov {include}
Glej tudi {include file}
Če želite blok natisniti na določenem mestu, uporabite oznako {include blockname}
:
<title>{block title}{/block}</title>
<h1>{include title}</h1>
Prikažete lahko tudi blok iz druge predloge:
{include footer from 'main.latte'}
Izpisani blok nima dostopa do spremenljivk aktivnega konteksta, razen če je blok definiran v isti datoteki, v katero je vključen. Imajo pa dostop do globalnih spremenljivk.
Spremenljivke lahko bloku posredujete na naslednji način:
{include footer, foo: bar, id: 123}
Kot ime bloka lahko uporabite spremenljivko ali kateri koli izraz v PHP. V tem primeru pred spremenljivko dodajte ključno
besedo block
, da se ob sestavljanju ve, da gre za blok, in ne za vstavljanje predloge, katere ime je lahko tudi v spremenljivki:
{var $name = footer}
{include block $name}
Blok se lahko izpiše tudi znotraj samega sebe, kar je uporabno na primer pri upodabljanju drevesne strukture:
{define menu, $items}
<ul>
{foreach $items as $item}
<li>
{if is_array($item)}
{include menu, $item}
{else}
{$item}
{/if}
</li>
{/foreach}
</ul>
{/define}
Namesto {include menu, ...}
lahko zapišemo tudi {include this, ...}
, kjer this
pomeni
trenutni blok.
Natisnjeno vsebino lahko spreminjamo s filtri. Naslednji primer odstrani ves HTML in ga označi z naslovi:
<title>{include heading|stripHtml|capitalize}</title>
Nadrejeni blok
Če morate vsebino bloka izpisati iz nadrejene predloge, bo to storila izjava {include parent}
. To je uporabno,
če želite dodati vsebino nadrejenega bloka, namesto da bi ga v celoti prepisali.
{block footer}
{include parent}
<a href="https://github.com/nette">GitHub</a>
<a href="https://twitter.com/nettefw">Twitter</a>
{/block}
Definicije {define}
Poleg blokov so v programu Latte na voljo tudi “definicije”. Te so primerljive s funkcijami v običajnih programskih jezikih. Uporabne so za ponovno uporabo fragmentov predlog, da se ne ponavljamo.
Latte poskuša stvari poenostaviti, zato so definicije v osnovi enake blokom in vse, kar je rečeno o blokih, velja tudi za definicije. Od blokov se razlikujejo po tem, da:
- zaprte so v oznake
{define}
. - se prikažejo samo, ko so vstavljene prek
{include}
- lahko jim določite parametre kot funkcijam v PHP
{block foo}<p>Hello</p>{/block}
{* prints: <p>Hello</p> *}
{define bar}<p>World</p>{/define}
{* ne natisne ničesar *}
{include bar}
{* prints: <p>World</p> *}
Predstavljajte si, da imate pomožno predlogo z zbirko definicij za risanje obrazcev HTML.
{define input, $name, $value, $type = 'text'}
<input type={$type} name={$name} value={$value}>
{/define}
{define textarea, $name, $value}
<textarea name={$name}>{$value}</textarea>
{/define}
Argumenti definicije so vedno neobvezni s privzeto vrednostjo null
, razen če je določena privzeta vrednost
(tukaj je 'text'
privzeta vrednost za $type
). Vrste parametrov je mogoče tudi deklarirati:
{define input, string $name, ...}
.
Predloga z definicijami se naloži z uporabo {import}
. Same definicije se
prikažejo na enak način kot bloki:
<p>{include input, 'password', null, 'password'}</p>
<p>{include textarea, 'comment'}</p>
Definicije nimajo dostopa do spremenljivk aktivnega konteksta, imajo pa dostop do globalnih spremenljivk.
Dinamična imena blokov
Latte omogoča veliko prilagodljivost pri opredeljevanju blokov, saj je lahko ime bloka poljuben izraz PHP. Ta primer
opredeljuje tri bloke z imeni hi-Peter
, hi-John
in hi-Mary
:
{foreach [Peter, John, Mary] as $name}
{block "hi-$name"}Hi, I am {$name}.{/block}
{/foreach}
Na primer, v podrejeni predlogi lahko na novo opredelimo samo en blok:
{block hi-John}Hello. I am {$name}.{/block}
Tako bo rezultat videti takole:
Hi, I am Peter.
Hello. I am John.
Hi, I am Mary.
Preverjanje obstoja blokov {ifset}
Glej tudi {ifset $var}
S testom {ifset blockname}
preverite, ali v trenutnem kontekstu obstaja blok (ali več blokov):
{ifset footer}
...
{/ifset}
{ifset footer, header, main}
...
{/ifset}
Kot ime bloka lahko uporabite spremenljivko ali kateri koli izraz v jeziku PHP. V tem primeru pred spremenljivko dodajte
ključno besedo block
, da bo jasno, da se ne preverja spremenljivka:
{ifset block $name}
...
{/ifset}
Obstoj blokov vrne tudi funkcija hasBlock()
:
{if hasBlock(header) || hasBlock(footer)}
...
{/if}
Nasveti
Tukaj je nekaj nasvetov za delo z bloki:
- Zadnjemu bloku najvišje ravni ni treba imeti zaključne oznake (blok se konča s koncem dokumenta). To poenostavi pisanje podrejenih predlog, ki imajo en primarni blok.
- Za večjo berljivost lahko po želji dodate ime oznaki
{/block}
, na primer{/block footer}
. Vendar se mora ime ujemati z imenom bloka. V večjih predlogah vam ta tehnika pomaga videti, katere blokovne oznake so zaprte. - V isti predlogi ne morete neposredno opredeliti več blokovnih oznak z istim imenom. To pa lahko dosežete z uporabo dinamičnih imen blokov.
- Z uporabo n:atributov lahko opredelite bloke, kot
so
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Bloki se lahko uporabljajo tudi brez imen samo za uporabo filtrov
na izhodu:
{block|strip} hello {/block}
Vodoravna ponovna uporaba {import}
Horizontalna ponovna uporaba je tretji mehanizem za ponovno uporabo in dedovanje v Latte. Omogoča nalaganje blokov iz drugih
predlog. Podobno je, kot če bi v PHP ustvarili datoteko s pomožnimi funkcijami in jo nato naložili z uporabo spletne strani
require
.
Čeprav je dedovanje postavitve predloge ena od najmočnejših funkcij sistema Latte, je omejeno na preprosto dedovanje – predloga lahko razširi le eno drugo predlogo. Horizontalna ponovna uporaba je način za doseganje večkratnega dedovanja.
Imejmo nabor definicij blokov:
{block sidebar}...{/block}
{block menu}...{/block}
Z ukazom {import}
uvozimo vse bloke in definicije, opredeljene v
blocks.latte
, v drugo predlogo:
{import 'blocks.latte'}
{* stranska vrstica in menijski bloki se zdaj lahko uporabljajo *}
Če bloke uvozite v nadrejeno predlogo (npr. uporabite ukaz {import}
v layout.latte
), bodo bloki na
voljo tudi v vseh podrejenih predlogah, kar je zelo priročno.
Predloga, ki je namenjena uvozu (npr. blocks.latte
), ne sme razširiti druge
predloge, tj. uporabite {layout}
. Lahko pa uvozi druge predloge.
Oznaka {import}
mora biti prva oznaka predloge za {layout}
. Ime predloge je lahko kateri koli
izraz PHP:
{import $ajax ? 'ajax.latte' : 'not-ajax.latte'}
V posamezni predlogi lahko uporabite poljubno število izrazov {import}
. Če dve uvoženi predlogi definirata
isti blok, zmaga prva. Vendar ima največjo prednost glavna predloga, ki lahko prepiše kateri koli uvoženi blok.
Vsebino prepisanih blokov lahko ohranite tako, da blok vstavite na enak način kot nadrejeni blok:
{layout 'layout.latte'}
{import 'blocks.latte'}
{block sidebar}
{include parent}
{/block}
{block title}...{/block}
{block content}...{/block}
V tem primeru bo {include parent}
pravilno poklical blok sidebar
iz predloge
blocks.latte
.
Dedovanje enot {embed}
Dedovanje enot prenaša idejo dedovanja postavitve na raven vsebinskih fragmentov. Medtem ko dedovanje postavitve deluje s “skeleti dokumentov”, ki jih oživijo predloge otrok, dedovanje enot omogoča, da ustvarite skelete za manjše enote vsebine in jih ponovno uporabite kjerkoli želite.
Pri dedovanju enot je ključna oznaka {embed}
. Združuje obnašanje oznak {include}
in
{layout}
. Z njo lahko vključite vsebino druge predloge ali bloka in po želji posredujete spremenljivke, tako kot
to počne {include}
. Omogoča tudi prekrivanje katerega koli bloka, opredeljenega znotraj vključene predloge, kot to
počne {layout}
.
Za primer bomo uporabili element zložljive harmonike. Oglejmo si ogrodje elementa v predlogi
collapsible.latte
:
<section class="collapsible {$modifierClass}">
<h4 class="collapsible__title">
{block title}{/block}
</h4>
<div class="collapsible__content">
{block content}{/block}
</div>
</section>
Oznake {block}
določajo dva bloka, ki ju lahko izpolnijo podrejene predloge. Da, tako kot v primeru starševske
predloge v predlogi za dedovanje postavitve. Vidite tudi spremenljivko $modifierClass
.
Uporabimo naš element v predlogi. Tu pride na vrsto {embed}
. To je izjemno zmogljiv pripomoček, ki nam omogoča
vse: vključiti vsebino predloge elementa, mu dodati spremenljivke in dodati bloke s prilagojenim HTML-jem:
{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}
Rezultat je lahko videti takole:
<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>
Bloki znotraj oznak embed tvorijo ločeno plast, neodvisno od drugih blokov. Zato imajo lahko enako ime kot blok zunaj vgradne
oznake in nanje to nima nobenega vpliva. Z uporabo oznake include znotraj oznak
{embed}
lahko vstavite tukaj ustvarjene bloke, bloke iz vstavljene predloge (ki ne so lokalni) in tudi bloke iz glavne predloge, ki so lokalni. Prav tako lahko uvozite bloke iz drugih datotek:
{block outer}…{/block}
{block local hello}…{/block}
{embed 'collapsible.latte', modifierClass: my-style}
{import 'blocks.latte'}
{block inner}…{/block}
{block title}
{include inner} {* deluje, blok je definiran znotraj embed *}
{include hello} {* deluje, blok je lokalni v tej predlogi *}
{include content} {* deluje, blok je opredeljen v vdelani predlogi *}
{include aBlockDefinedInImportedTemplate} {* deluje *}
{include outer} {* ne deluje! - blok je v zunanji plasti *}
{/block}
{/embed}
Vgrajene predloge nimajo dostopa do spremenljivk aktivnega konteksta, imajo pa dostop do globalnih spremenljivk.
S spletno stranjo {embed}
lahko poleg predlog vstavite tudi druge bloke, zato bi lahko prejšnji primer zapisali
takole:
{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}
Če posredujemo izraz {embed}
in ni jasno, ali gre za ime bloka ali datoteke, dodamo ključno besedo
block
ali file
:
{embed block $name} ... {/embed}
Primeri uporabe
V sistemu Latte obstajajo različne vrste dedovanja in ponovne uporabe kode. Za večjo jasnost povzemimo glavne koncepte:
{include template}
Primer uporabe: Uporaba header.latte
in footer.latte
znotraj layout.latte
.
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}
Primer uporabe: Razširitev layout.latte
znotraj homepage.latte
in
about.latte
.
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}
Primer uporabe: sidebar.latte
v single.product.latte
in 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}
Primer uporabe: Funkcija, ki dobi nekaj spremenljivk in izpiše nekaj oznak.
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}
Primer uporabe: Vstavljanje pagination.latte
v product.table.latte
in
service.table.latte
.
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}