Tento návod se primárně zaměřuje – jak název napovídá – na vytvoření galerie, přičemž požadovaným výstupem bude náhodný výběr stanoveného počtu obrázků z předem neznámého počtu a jejich zobrazení na stránce. Současně ale prezentuje i možnosti značkovacího jazyka pro tvorbu šablon Twig a rovněž i možnosti značkovacího jazyka pro formátování obsahu Markdown. Okrajově pak představuje možnosti ukládání stránek do mezipaměti, nebo chcete-li do cache.
Ukázka funkční galerie dle tohoto návodu je k dispozici na webu Z&D stavby, s.r.o., avšak tato již obsahuje i některá rozšíření. K datu vydání článku se ještě pracuje na komplexní grafické stránce webu.
Jak již bylo uvedeno v článku Úložiště médií a možnosti přístupů k médiím, je v Gravu možné uložit soubory, potažmo pak obrázky, do několika úložišť, zvolených podle následujícího očekávání, konkrétně pak, zda budou užívány pouze v konkrétní stránce, nebo v rámci celého webu. Galerie je typickým příkladem první varianty, nicméně nic nebrání tomu, abychom obrázky následně použili na kterékoliv jiné stránce.
Začneme tedy vytvořením stránky /galerie
a nahráním kolekce obrázků do této stránky. Pro naši potřebu je ideální, aby měly nastaveno výchozí třídění, tedy podle svého názvu, ale v konečném důsledku na tom nezáleží, protože budeme ve výstupu pracovat s náhodně uspořádanými hodnotami, z nichž použijeme pouze zvolenou část. Pokud tedy použijeme vlastní třídění prostřednictvím proměnné hlavičky stránky media_order
, není to na překážku. Z článku Úložiště médií a možnosti přístupů k médiím víme, že soubory/obrázky uložené v konkrétní stránce jsou ze strany Gravu chápány jako Média stránky, a tyto jsou dostupné v proměnné stránky typu pole page.media
. Abychom mohli s jednotlivými obrázky pracovat, je třeba je nejprve z pole načíst a upravit.
Galerie implementované v některých dostupných šablonách pracují odlišně, neboť nepřistupují přímo k proměnné page.media
, ale prostřednictvím vlastní proměnné hlavičky stránky, např. page.header.gallery
, v níž se nachází seznam konkrétně vybraných obrázků, které se mají v galerii zobrazit, ačkoliv stránka může obsahovat obrázků podstatně více. Uvedené řešení je pro potřeby kompletního procházení médií nepoužitelné, pokud by nebyly všechny uvedeny explicitně v proměnné hlavičky stránky page.header.gallery
. To se dá ohlídat v rámci jednotek souborů, avšak již nikoliv v rámci desítek či stovek nahraných médií.
V ukázce budeme pracovat pouze s názvy souborů, nicméně je možné z nich získat i další informace, jako velikost, rozlišení, typ apod., které lze dále zpracovat a použít.
Nejprve si ukážeme jednoduchou variantu, která náhodně vybere vzorek obrázků z kolekce:
{% for image in page.media %}
{% if random(100) < 10 %}
{{ image.cropZoom(400, 400) }}
{% endif %}
{% endfor %}
Zápis v Twigu {{ image.cropZoom(400, 400) }}
odpovídá zápisu v Markdownu ![](/image001.png?cropZoom(400, 400))
s tím rozdílem, že v Twigu je slovo image
proměnná, kdežto v Markdownu tvoří název souboru. V obou případech jsou pro zjednodušení vynechány parametry Alt
a Title
.
Uvedený kód prochází všechny obrázky uložené ve složce stránky. V rámci cyklu for
generuje náhodná čísla v intervalu <0; 100>
a v případě, že je číslo menší než 10, pak obrázek vykreslí, v opačném případě pokračuje v procházení. Pokud tedy máme v kolekci např. 320 obrázků, mělo by se jich na stránce zobrazit přibližně 32, což odpovídá 10 % celku.
Proč přibližně? Protože nelze nijak zaručit, že náhodná čísla budou generována zcela rovnoměrně v rámci celého rozsahu, avšak obvykle tomu tak skutečně je. Může pochopitelně nastat situace, kdy čísel menších než stanovená hranice bude více, čímž se vykreslí i více obrázků, a naopak. Orientačním testováním se prokázala odchylka cca 1 %, tj. v případě celkového počtu 100 obrázků je výstupem cca 9-11 obrázků. Na uvedené nemá vliv rozsah, tj. zda je 100/10, nebo např. 1000/100.
Funkce random
se v Twigu chová odlišně, než v běžných programovacích jazycích, v nichž obdobná funkce obvykle vrací náhodné číslo v intervalu <0; 1)
, a to s přesností na několik míst za desetinnou čárkou. Při maximální hodnotě 0,999999 je tedy k dispozici 1 000 000 čísel, ve skutečnosti se ale pohybujeme v podstatně větších rozsazích. Teprve až následnou úpravou – obvykle násobením a zaokrouhlením – získáme požadované hodnoty ve vlastním rozsahu, pokud nechceme přímo zpracovat výchozí hodnoty, např. {{ if i < 0,5 }}
. Funkce random
vrací čísla přímo v celočíselném datovém typu integer
. Z předchozího je zřejmé, že funkcí random(100)
získáme 101 čísel, což může vést ke zkreslení výsledků, neboť je evidentní, že pro nezobrazení obrázků je k dispozici 1 hodnota navíc. Pokud bychom chtěli 100 čísel, musela by horní hranice odpovídat číslu 99.
Předchozí příklad má řadu nedostatků. Kromě toho, že není možné ovlivnit přesný počet obrázků, které budou vráceny ve výstupu, je rovněž skutečností, že obrázky jsou vždy řazeny ve shodném pořadí, což může – i nemusí – být překážkou, záleží na úhlu pohledu. Zásadní nevýhodou je pak variabilita, která se projeví při přidání (obecně změně) dalších obrázků. Pokud se nyní vrací cca 10 % obrázků z celkového počtu, pak při 1000 obrázcích by to již bylo okolo 100, což může vést ke zpomalení načítání stránky. V tomto případě bychom museli při každé změně nahraných obrázků upravit hodnotu ovlivňující výstup, např. na {% if random(100) < 2 %}
, nebo zajistit ošetření podmínkami pro jednotlivé intervaly v kódu.
Vrátíme se tedy k původnímu zadání, které bude fungovat tak, že se vždy zobrazí shodný počet obrázků, a to ve zcela náhodném pořadí. K tomu použijeme následující Twig kód:
{% set images = [] %}
{% for image in page.media %}
{% set key = random(1000) %}
{% set images = images + ({(key): image}) %}
{% endfor %}
Čistší zápis řádku {% set images = images + ({(key): image}) %}
by byl {% set images = images|merge({(key): image}) %}
, ale bohužel v případě dynamického přidělování klíčů a hodnot nefunguje. Uvedený alternativní zápis naopak funguje zcela bez problémů.
Kód si podrobně vysvětlíme. Nejprve vytvoříme prázdnou proměnnou typu pole images
. Dále procházíme cyklem for
kolekci obrázků, tedy jednotlivá média stránky, která postupně přiřazujeme do proměnné image
. V následujícím kroku vygenerujeme náhodné číslo v intervalu <0; 1000>
. A nakonec je tu nejdůležitější část, v rámci níž do dříve vytvořené proměnné typu pole images
přidáváme položky ve dvojici klíč: hodnota
, kdy klíčem je aktuálně vygenerované náhodné číslo a hodnotou aktuální položka přiřazená do proměnné image
. Uvedeným kódem jsme docílili toho, že máme k dispozici indexované pole, obsahující teoreticky všechny obrázky, přičemž každý má přiřazený jedinečný celočíselný identifikátor v rozsahu stanoveném intervalem, který nám umožní další manipulaci dle našich potřeb.
Proč teoreticky všechny obrázky? Pokud je vygenerováno náhodné číslo, které již bylo použito, je původní dvojice klíčX: hodnotaA
nahrazena novou dvojicí klíčX: hodnotaB
. Tím může nastat situace, že v poli images
je menší počet položek, než bylo v původním poli page.media
. Vzhledem k tomu, že budeme dále pracovat pouze se zlomkem tohoto výstupu, není to žádnou překážkou.
Nyní již nic nebrání tomu, abychom data upravili a vypsali na stránku. K tomu slouží následující Twig kód.
{% set images = images|ksort %}
{% set images = images|slice(0, 10) %}
{% for image in images %}
{{ image.cropZoom(400, 400) }}
{% endfor %}
Kód si opět podrobně vysvětlíme. V prvním kroku setřídíme pole images
vzestupně podle hodnot klíčů. Jelikož jsou klíče tvořeny náhodnými hodnotami, dojde k náhodnému „zamíchání“ obrázků, čehož jsme přesně chtěli dosáhnout.
Ke třídění podle hodnot klíčů použijeme filtr ksort
. Přestože se o něm dokumentace Twig nezmiňuje (oficiálně je k dispozici pouze filtr sort
), tak funguje zcela podle očekávání.
Ze setříděných obrázků dále použijeme pouze podmnožinu sestávající z prvních N prvků, v našem případě 10. K tomu nám poslouží filtr slice
.
Filtr slice
– stejně jako většina filtrů – počítá prvky počínaje indexem 0, druhé číslo uvádí počet vrácených hodnot.
A nakonec jednotlivé obrázky, resp. jejich náhledy, vykreslíme na stránce.
Zde je k dispozici kompletní kód:
{% set images = [] %}
{% for image in page.media %}
{% set key = random(1000) %}
{% set images = images + ({(key): image}) %}
{% endfor %}
{% for image in images|ksort|slice(0, 10) %}
{{ image.cropZoom(400, 400) }}
{% endfor %}
Porovnejte úsporný zápis kódu na řádku {% for image in images|ksort|slice(0, 10) %}
s rozepsaným kódem uvedeným v předchozí části.
V příkladech není ošetřena možnost, že médii mohou být i jiné soubory než obrázky. Je třeba to mít na zřeteli! Pokud chceme procházet místo všech médií pouze obrázky, pak je třeba upravit kolekci z page.media
na page.media.images
.
Kód můžeme vložit buď do nové šablony stránky gallery.html.twig
, za předpokladu, že plánujeme na webu více galerií, popř. přímo do těla stránky, pokud se jedná spíše o ojedinělou záležitost. V tomto případě je nutné aktivovat položku Twig v nastavení Zpracování stránky (výchozí je pouze Markdown), stejně jako například v příkladu konverze znaků v Twig šabloně.
Grav stránky ukládá do mezipaměti, aby urychlil jejich načítání. K jejich opětovnému vygenerování dochází pouze v případě změny obsahu nebo po vyprázdnění mezipaměti (po vypršení určené doby, po ručním vymazání, nebo vymazání prostřednictvím plánovače úloh). To má za následek, že se načítá stránka z mezipaměti, dokud nenastane některá ze situací, která způsobí její opětovné vygenerování. Existuje proto alternativní – avšak nijak elegantní – řešení, a to vypnout ukládání do mezipaměti na úrovni stránky nastavením položky Použít cache na Vypnuto. Tímto zajistíme, že je při každém načtení stránka opětovně vytvořena znovu. Rychlost vytvoření a zobrazení stránky je závislá jednak na počtu celkových médií stránky, které se musí projít, ale především na počtu těch, které chceme na výstupu, neboť se musí opakovaně generovat jejich náhledy, jako se tomu děje v příkladu výše. Horší variantu, kdy server předává prohlížeči originály obrázků v plné velikosti radši ani nedomýšlet.
Důkazem, že Grav je skutečně propracovaný CMS do všech detailů je skutečnost, že umožňuje v dílčím nastavení obsah stránek ukládat do mezipaměti, ale s vyloučením zpracování Twigu. To znamená, že veškerý „statický“ obsah včetně značkování Markdown je zpracován a uložen do mezipaměti, zatímco „dynamické“ části tvořené Twigem se vždy generují znovu. Vzhledem k tomu, že galerie je kompletně generována Twigem, nemá uvedené nastavení v tomto případě žádný vliv.
Skutečně nejlepší řešení je v tomto případě mezipaměť používat a v pravidelných intervalech ji čistit prostřednictvím plánovače úloh. Vhodný interval je skutečně individuální a záleží na několika faktorech, jako je návštěvnost, počet stránek apod.
A to je vše. Nyní zbývá pouze graficky upravit výstup prostřednictvím stylů, popř. zvolit jiný typ generovaných náhledů (měřítko, oříznuté měřítko), či rozšířit o jiný prvek, např. výstup parametrů Alt
a/nebo Title
, prohlížeč zvětšenin obrázků (viz odkaz na funkční galerii v úvodu článku), vodoznak apod.
Nalezli jste v článku chybu, ať již gramatickou nebo faktickou? Článek prošel pouze autorskou korekturou a drobné nedostatky, jako překlepy nebo chybný slovosled, se v něm mohou vyskytovat. Pokud je objevíte, pomozte příspěvek upravit oznámením přes kontaktní formulář nebo na e-mail. Budou vám vděčni nejen autoři, ale zejména ostatní čtenáři.
Pomozte Grav.cz prolinkovat. Projekt Grav.cz se za dva roky provozu rozrostl a ve starších příspěvcích na Blogu mohou být uvedeny pasáže, které by stálo za to prolinkovat na konkrétní související řešení, která jsou uvedena v následujících příspěvcích. Pokud takové objevíte, pošlete informaci přes komunikační kanály uvedené v předchozím nebo následujícím odstavci.
Diskuze k článku není k dispozici. Pokud ale máte k tématu článku podněty, připomínky nebo dotazy, je možné je sdělit ve skupině na Facebooku, kde se k nim vyjádří nejen autor, ale případně i další diskutující.