On Github lyrixx / SFLive-Paris2013-Twig
Grégoire Pineau - Symfony Live - Paris 2013
php composer.phar require twig/twig:~1.12
// twig.php require __DIR__.'/vendor/autoload.php'; $loader = new Twig_Loader_Filesystem(array(__DIR__.'/templates')); $twig = new Twig_Environment($loader);
Template:
{# hello.html.twig #} hello {{ name }}
Php:
// hello.php require __DIR__.'/twig.php'; echo $twig->render('hello.html.twig', array('name' => 'greg'));
Résultat:
hello greg
Pourquoi ? Quand ?
{# layout.html.twig #} <html> <head> <title>{% block title '' %}</title> {% block meta '' %} {% block css %} <style type="text/css" src="/css/styles.css"></style> {% endblock %} </head> <body> Navigation Fil d'arianne {% block body '' %} {% block javascripts '' %} </body> </html>
{# homepage.html.twig #} {% extends 'layout.html.twig' %} {% block title 'Ma page' %} {% block css %} {{ parent() }} <style type="text/css" src="/css/homepage.css"></style> {% endblock %} {% block body %} Coverflow Boutons {% endblock %}
<html> <head> <title>Ma page</title> <style type="text/css" src="/css/styles.css"></style> <style type="text/css" src="/css/homepage.css"></style> </head> <body> Navigation Fil d'arrianne Coverflow Boutons </body> </html>
Pourquoi ? Quand ?
{# qui-sommes-nous.html.twig #} <div> Qui sommes nous ? </div>
::
{# homepage.html.twig #} <div> New </div> <div> Derniers Commentaires </div> {{ include('qui-sommes-nous.html.twig') }}
{# news.html.twig #} {% for post in posts %} {{ include('post.html.twig', { post: post }, with_context = false) }} {% endfor %}
::
{# post.html.twig #} <div> <h3>{{ post.title}}</h3> <div>{{ post.content }}</div> </div>
Pourquoi ? Quand ?
{# blocks.html.twig #} {% block qui_sommes_nous %} <div> Qui sommes nous ? </div> {% endblock %}
::
{# homepage.html.twig #} {# ... #} {% use "blocks.html.twig" %} {{ block('qui_sommes_nous') }} {# OU #} {% block qui_sommes_nous %} <div class="container"> {{ parent() }} </div> {% endblock %}
Pourquoi ? Quand ?
{# news.html.twig #} {% for post in posts %} {% embed "post.html.twig" with { post: post } only %}{% endembed %} {% endfor %}
{# post.html.twig #} <div> {% block title %}<h3>{{ post.title}}</h3>{% endblock %} {% block content%}<div>{{ post.content }}</div>{% endblock %} {% block metas %} <p>Par {{ post.author }} le {{ post.date }}</p> {% endblock %} {% block comments %} <p>il y a {{ post.comment|length }} commentaires</p> {% endblock %} </div>
{# homepage.html.twig #} <div> {% embed "embed/post.html.twig" with { post: posts|last } only %} {% block title %} <h1>{{ post.title}}</h1> {% endblock %} {% block comments %} {{ parent() }}<p>Lire les commentaire</p> {% endblock %} {% endembed %} </div> <div> Derniers Commentaires </div> {{ include('include/qui-sommes-nous.html.twig') }}
Pourquoi ? Quand ?
{% macro input(name, type = 'text', value = '', size = '20') %} {% spaceless %} <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" /> {% endspaceless %} {% endmacro %} {% import _self as forms %} {# ou #} {% import 'forms.html.twig' as forms %} {{ forms.input('user') }} {{ forms.input('email', 'email') }}
Vous voulez:
Note:
Les fonctions twig ne sont pas faites pour générer du HTML ; Il en sera question un peu plus loin
Comment construire un systeme de thème ?
Use case:
themes ├── default │ ├── footer.html.twig │ ├── header.html.twig │ ├── homepage.html.twig │ └── layout.html.twig └── my_theme └── header.html.twig
{# default/layout.html.twig #} <html> <head> <title>{% block title '' %}</title> </head> <body> {{ include('logo.html.twig') }} {% block content '' %} </body> </html>
{# default/homepage.html.twig #} {% extends 'layout.html.twig' %} {% block content %} Du contenu {% endblock %}
::
{# default/logo.html.twig #} <img src="logo.png">
{# my_theme/logo.html.twig #} <h1>Mon site</h1> <img src="mon-logo.png">
<html> <head> <title></title> </head> <body> <h1>Mon site</h1> <img src="mon-logo.png"> Du contenu </body> </html>
require __DIR__.'/vendor/autoload.php'; $loader = new Twig_Loader_Filesystem(array( __DIR__.'/templates/theming/my_theme', __DIR__.'/templates/theming/default', )); $twig = new Twig_Environment($loader); echo $twig->render('homepage.html.twig'); // <--- /!\ Attention
themes ├── default │ ├── footer.html.twig │ ├── header.html.twig │ ├── homepage.html.twig │ └── layout.html.twig └── my_theme ├── homepage.html.twig └── header.html.twig
{# my_theme/homepage.html.twig #} {% extends 'default/homepage.html.twig' %} {% block content %} <div class="container"> {{ parent() }} </div> {% endblock %}
Il faut ajouter le répertoire commun aux deux dossiers de thème :
require __DIR__.'/vendor/autoload.php'; $loader = new Twig_Loader_Filesystem(array( __DIR__.'/templates/theming/my_theme', __DIR__.'/templates/theming/default', __DIR__.'/templates/theming', // <---- HERE )); $twig = new Twig_Environment($loader); echo $twig->render('homepage.html.twig');
Mais pourquoi Wordpress n'utilise pas twig pour ses templates ??????????????????
Comment personaliser l'affichage des fonctions twig ?
Use case:
Note: Ici un include / embed ne peut pas suffir, car il y a potentiellement des besoins métiers (appel à la BDD, ...) qui ne peuvent / doivent pas etre fait depuis une template.
{# layout.html.twig #} {{ display_menu(page|default(null)) }}
::
<!-- Résultat --> <nav> <ul> <li><a href="#">A</a></li> <li><a href="#">B</a></li> <li><a href="#">C</a></li> </ul> </nav>
display_menu est une fonction twig qui va générer du contenu HTML.
Nous voulons un support pour display_menu, display_flash, display_pagination, display_slider, display_*
Pour ajouter ces fonctions à twig, Nous allons:
class DisplayExtension extends \Twig_Extension { private $themes; public function __construct(array $themes = array()) { $this->themes = $themes; } }
public function getFunctions() { return array( new \Twig_SimpleFunction( 'display_menu', array($this, 'displayBlock'), array('needs_environment' => true, 'is_safe' => array('html')) ), ); }
public function displayBlock(\Twig_Environment $env, $block = 'menu', $parameters = array()) { foreach ($this->themes as $theme) { if ($theme instanceof \Twig_Template) { $template = $theme; } else { $template = $env->loadTemplate($theme); } if ($template->hasBlock($block)) { return $template->renderBlock($block, $parameters); } } throw new \InvalidArgumentException('Unable to find block '.$block); }
Attention: Ici on utilise une partie de l'API de twig qui n'est pas publique *
$twig->addExtension(new DisplayExtension(array('display.html.twig')));
{# display.html.twig ; Notre template de blocks #} {% block menu %} {% spaceless %} <nav> <ul> <li><a href="#">A</a></li> <li><a href="#">B</a></li> <li><a href="#">C</a></li> </ul> </nav> {% endspaceless %} {% endblock %} {% block pagination %} {# ... #} {% block slider %} {# ... #} {% block flash %} {# ... #}
public function getFunctions() { return array( new \Twig_SimpleFunction( 'display_menu', array($this, 'displayMenu'), array('needs_environment' => true, 'is_safe' => array('html')) ), new \Twig_SimpleFunction( 'display_*', array($this, 'displayBlock'), array('needs_environment' => true, 'is_safe' => array('html')) ), ); }
public function displayMenu(\Twig_Environment $env, $page = null) { // Do what you need HERE. return $this->displayBlock($env, 'menu', array('page' => $page)); }
Il faut ajouter un tag, qui va ajouter à la compilation un nouveau thème pour la template courante.
Le code est un peu compliqué, mais il sera dans le dépôt ;)
{# page.html.twig #} {% extends 'layout.html.twig' %} {% display_theme _self %} {% block menu %} <h6>Menu:</h6> <nav class="class4"> <ul class="class5"> <li><a href="#">A</a></li> <li><a href="#">B</a></li> <li><a href="#">C</a></li> </ul> </nav> {% endblock %} {{ display_menu(page|default(null)) }}
<!-- Résultat --> <h6>Menu:</h6> <nav class="class4"> <ul class="class5"> <li><a href="#">A</a></li> <li><a href="#">B</a></li> <li><a href="#">C</a></li> </ul> </nav>
Les slides:
Sinon:
Et: