Symfony po krůčkách – Twig

V dnešním díle si představíme výchozí symfoňácký šablonovací systém – Twig, který nám umožňuje krásně oddělit aplikační vrstvu od prezentační. Díky šablonám nemusíte (a ve Twigu ani nemůžete) míchat PHP a HTML kód. Další výhodou Twigu je bezesporu zvýšení bezpečnosti vaší aplikace za pomocí automatického escapování obsahu proměnných.

Seriál: Symfony po krůčkách (18 dílů)

  1. Symfony po krůčkách – Event Dispatcher 30.11.2015
  2. Symfony Console jako první rande se Symfony 7.12.2015
  3. Symfony po krůčkách – Filesystem a Finder 14.12.2015
  4. Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání 21.12.2015
  5. Symfony po krůčkách – spouštíme procesy 4.1.2016
  6. Symfony po krůčkách – Translation – překlady jednoduše 11.1.2016
  7. Symfony po krůčkách – Validator (1) 18.1.2016
  8. Symfony po krůčkách – Validator (2) 25.1.2016
  9. Symfony po krůčkách – Routing 1.2.2016
  10. Symfony po krůčkách – MicroKernel 9.2.2016
  11. Konfigurujeme Symfony pomocí YAMLu 16.2.2016
  12. Symfony po krůčkách – oblékáme MicroKernel 23.2.2016
  13. Symfony po krůčkách – ClassLoader 29.2.2016
  14. Symfony po krůčkách – Twig 8.3.2016
  15. Symfony po krůčkách – Twig II. 15.3.2016
  16. Symfony po krůčkách – DomCrawler a CssSelector 23.3.2016
  17. Symfony po krůčkách – HTTP fundamentalista 12.4.2016
  18. Symfony po krůčkách – ušli jsme pořádný kus 19.4.2016

Základní syntaxe Twigu

Potřebujeme znát 3 základní syntaktické konstrukce:

  • {{ … }} něco říká, používá se např. pro vykreslení proměnné.
  • {% … %} něco dělá a používá se v případě, kdy v šabloně potřebujeme nějakou logiku, například definovat proměnnou, zapsat podmínku nebo třeba importovat jinou šablonu.
  • {# … #} něco komentuje.

Příklad na úvod

Všechny zdrojáky najdete v repozitáři na GitHubu.

Twig nainstalujeme pomocí Composeru

composer require twig/twig

Vytvoříme jednoduchý skript, který bude vykreslovat šablonu Resources/views/index.html.twig. Vystačíme si se dvěma třídami:

  • Twig_Loader_Filesystem – třída zajišťující načítání šablon. V konstruktoru jednoduše nastavíme cestu ke složce, ve které má šablony hledat.
  • Twig_Environment – slouží ke konfiguraci našeho Twig prostředí. Jako první parametr přebírá implementaci Twig_LoaderInterface, která se bude používat pro načítání šablon.  V našem případě je to právě Twig_Loader_Filesystem.
//index.php
require_once __DIR__ . '/vendor/autoload.php';

$loader = new Twig_Loader_Filesystem('Resources/views');
$twig = new Twig_Environment($loader);

echo $twig->render('index.html.twig', ['name' => 'world']);
// Hello world!

Metodou $twig->render() vykreslíme šablonu, kterou definujeme jako první parametr. Druhým parametrem si do šablony můžeme předat pole proměnných. Naše základní šablona pak vypadá takto:

{# index.html.twig #}
Hello {{ name }}!

Přístup k atributům objektu a prvkům pole

Do šablony si můžeme předat i pole nebo objekt, k jehož prvkům (resp. properties) pak můžeme přistupovat unifikovaným způsobem pomocí tečky:

{# index.html.twig #}
My favourite movie: {{ movie1.title }}<br>
My friends favourite movie: {{ movie2.title }}
//index.php
require_once __DIR__ . '/vendor/autoload.php';

class Movie {

 /**
  * @var string
  */
 private $title;

 /**
  * @param string $title
  */
 public function __construct($title) {
  $this->title = $title;
 }

 /**
  * @return string
  */
 public function getTitle() {
  return $this->title;
 }
}

$loader = new Twig_Loader_Filesystem('Resources/views');
$twig = new Twig_Environment($loader);

$movieAsObject = new Movie('Kill Bill');
$movieAsArray = ['title' => 'Matrix']; 

echo $twig->render('index.html.twig', [
 'movie1' => $movieAsObject, 
 'movie2' => $movieAsArray, 
]);
// My favourite movie: Kill Bill
// My friends favourite movie: Matrix

Cykly, podmínky, operátory

Ve Twigu můžeme používat i cykly a podmínky, k dispozici máme navíc i rozsáhlou sadu operátorů, díky kterým je práce se šablonami zase o něco jednodušší. Operátory můžeme rozdělit na

  • logické (např. and, or)
  • porovnávací/testovací (např. ==, is not, empty nebo matches, pokud chceme používat regulární výrazy)
  • a další (např. ~ pro konkatenaci stringů, ternární operátor ?: nebo samozřejmě klasické matematické operátory pro sčítání, odčítání atd.).

Abychom nezůstávali dlouho u teorie, ukažme si jednoduchý příklad použití v kódu:

//index.php
require_once __DIR__ . '/vendor/autoload.php';
class Movie {

 /**
  * @var string
  */
 private $title;

 /**
  * @var string|null
  */
 private $comment;

 /**
  * @param string $title
  * @param string|null $comment
  */
 public function __construct($title, $comment = null) {
  $this->title = $title;
  $this->comment = $comment;
 }

 /**
  * @return string
  */
 public function getTitle() {
  return $this->title;
 }

 /**
  * @return string|null
  */
 public function getComment() {
  return $this->comment;
 }
}

$loader = new Twig_Loader_Filesystem('Resources/views');
$twig = new Twig_Environment($loader);

$movies = [
 new Movie('Reservoir Dogs'),
 new Movie('Jackie Brown'),
 new Movie('Grindhouse'),
 new Movie('Pulp Fiction', 'Oscar for Best Writing'),
 new Movie('Kill Bill'),
];

echo $twig->render('index.html.twig', [
 'movies' => $movies,
]);
{# index.html.twig #}
Quentin Tarantino movies: <br>
<ul>
 {% for movie in movies %}
  <li>
     {{ movie.title }}
     {% if movie.comment is not null %}
        - <i>{{ movie.comment }}</i>
     {% endif %}
  </li>
 {% endfor %}
</ul>

Co ještě Twig umí?

 Filtry a funkce

Filtry nám slouží nejčastěji k formátování zobrazovaných dat. Užitečné filtry jsou např. length, za jehož pomoci zjišťujeme počet prvků v poli, date pro formátování data, number_format pro formátování čísel nebo trim pro odřezání bílých znaků. Filtr aplikujeme jednoduše pomocí svislítka.

{{ movies|length }}

Funkce většinou provádějí nějakou pokročilejší logiku. Jako příklad funkce může posloužit třeba constant() pro vypisování hodnot PHP konstant. Funkci pak voláme přesně tak, jak by programátor očekával:

{{ constant('Component\\Constraint::MAX_VALUE') }}

Další užitečnou funkcí může být date() pro získání aktuálního data, která funguje obdobně jako v PHP.

{{ date(-2days) }}

Seznam všech funkcí a filtrů najdeme v oficiální dokumentaci.

Filtry a funkce si navíc můžeme vytvářet i vlastní, což si popíšeme v příštím díle.

Dědičnost šablon

Další fantastickou vlastností Twigu je možnost tvořit hierarchii šablon pomocí dědičnosti. Díky tomu lze například vytvořit šablonu, která bude sloužit jako kostra pro základní layout, a tu budou ostatní šablony rozšiřovat pomocí přepisování konkrétních bloků. Dědičnost se definuje pomocí tagu extends.

{# base.html.twig #}
<html>
    <head>
        <meta charset="UTF-8">
        <title>Twig - {% block title %}{% endblock %}</title>
    </head>
    <body>
        <div id="menu">
            This is menu
        </div>
        <div id="main_content">
            {% block main_content %}{% endblock %}
        </div>
    </body>
</html>
{# index.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}
    Index page
{% endblock %}

{% block main_content %}
   This is main content
{% endblock %}

Ve výsledku pak uživatel na stránce uvidí toto:

This is menu
This is main content

Escapování

Jak už bylo zmíněno v úvodu, automatické escapování obsahu proměnných je jednou z klíčových vlastností šablonovacích systémů, Twig nevyjímaje. Pokud totiž v šabloně vykresluji proměnnou, je zde vždy riziko, že bude obsahovat znaky, které mohou výsledné HTML rozbít. Navíc pokud na escapování zapomenu, jsem vystaven riziku napadení své aplikace XSS útokem.

Ve Twigu je escapování defaultně zapnuto pro HTML, takže se o něj jako programátor nemusím vůbec starat. Jsou ovšem případy, kdy potřebuji escapování zakázat, např. pokud mám v proměnné naformátovaný obsah článku. V takovém případě můžu použít filtr

{{ article.text|raw }}

Mám taky možnost v konfiguraci escapování zakázat úplně a postarat se o něj ručně, a to hned několika možnými způsoby:

  • Pomocí filtru
{{ user.username|escape }}
  • nebo zkráceně
{{ user.username|e }}
  • nebo pomocí tagu
{% autoescape %}
  {{ user.username }}
{% endautoescape %}

Twig také umožňuje změnit strategii escapování (css, js, url, html_attr), což  lze opět provést buď v konfiguraci

new Twig_Environment($loader, ['autoescape' => 'url']);

nebo při používání filtru

{{ urlAddress|e('url') }}

případně při používání tagu

{% autoescape 'url' %}
   {{ urlAddress }}
{% endautoescape %}

Zase o krok dále

Dnes jsme se dozvěděli,

  • že díky používání Twigu máme zajištěno automatické escapování a přehlednější zdrojáky
  • že Twig umí spoustu užitečných věcí, jako je třeba dědičnost šablon
  • že použití Twigu v naší aplikaci je opravdu hračka

Co nás čeká příště?

V dalším díle se na Twig podíváme ještě podrobněji. Na co se můžete těšit?

  • Twig Extensions a integrace Twigu v Symfony,
  • používání překladů v šablonách,
  • tvorba vlastní funkce a filtru,
  • makra,
  • maily a další možnosti využití šablon

Vystudoval jsem softwarové inženýrství na FEI v Ostravě a od září 2014 pracuji v ShopSys jako vývojář nové e-commerce platformy postavené na Symfony frameworku.

Komentáře: 33

Přehled komentářů

Oldis
Karlos
Jarda
hatto Re:
Lukáš Brzák Re: Jarda
rapemer Re:
Lukáš Brzák Rozšiřování Twigu
Rostislav Vítek Re: Rozšiřování Twigu
Lukáš Brzák Re: Rozšiřování Twigu
zajca
Taco Re:
Rostislav Vítek Re:
Taco Re:
Rostislav Vítek Re:
Miroslav Šustek Re:
Taco Re:
takyhonza Re:
petrsoukup Re:
takyhonza Re:
Nette fanboy Re:
Taco Re:
Pavel Re:
Rostislav Vítek Re:
it expert Jinja
petrsoukup Re: Jinja
Ivan
podhy Re:
podhy sandbox
Adam
podhy Re:
Adam
podhy Re:
zvedavec Re:
Zdroj: https://www.zdrojak.cz/?p=17870