Drupal 8:
Twig Template
Engine
Drupal Meetup Stuttgart 4.10.2012 - drubb
Was ist eine Template Engine?

 ●    Eine Template Engine ersetzt in einer statischen Datei (dem Template) bestimmte Platzhalter
      durch variable Inhalte, ähnlich einer Seriendruckfunktion.
 ●    Dadurch soll eine Trennung von Programmlogik (z.B. PHP) und Markup (z.B. HTML) erreicht
      werden - zumindest in der Theorie.

Beispiel für ein Template, z.B. als Datei 'kunden.html':
<p>Kundenliste</p>
<ul>
<f:for each="{kunden}" as="eintrag">
<li>{eintrag vorname} {eintrag.nachname}</li>
</f:for>
</ul>

Die Template Engine muss hier nach Platzhaltern suchen und diese durch die eigentlichen Inhalte
ersetzen. PHP kann natürlich selbst als Template-Sprache verwendet werden. Beispiel:

<h1><?php echo $body_text ; ?></h1>

<?php foreach($test_array as $key => $value) : ?>
   <p>Schlüssel: <?php echo $key; ?> - Wert: <?php echo $value; ?></p>
<?php endforeach ; ?>

Bekannte Template Engines für PHP sind z.B. Smarty, Fluid (Typo3), PHPTal oder Contemplate.
Template Engines für Drupal

Drupal 4.5: erste Template Engine XTemplate
Drupal 4.7: PHPTemplate als beliebteste Engine

Alternative Engines optional auf d.o. verfügbar, z.B.

XTemplate, http://drupal.org/project/xtemplate (bis Drupal 4.7)
Smarty, http://drupal.org/project/smarty (bis Drupal 6)
PHPTAL, http://drupal.org/project/phptal (auch für Drupal 7)

PHPTemplate wurde erst in Drupal 7 endgültig Standard. Vorher musste die verwendete
Template Engine ausdrücklich im .info File des Themes angegeben werden:
name = Garland
description = Tableless, recolorable, multi-column, fluid width theme (default).
version = VERSION
core = 6.x
engine = phptemplate
stylesheets[all][] = style.css
stylesheets[print][] = print.css


Zusätzliche Engines konnten (und können nach wie vor) in das Verzeichnis /themes/engines
installiert werden, für entsprechende Themes die darauf basieren. Das hat sich aber in der Praxis
nicht durchgesetzt.
Schwachstellen der PHPTemplate Engine

 ●   Drupal-spezifisch
 ●   PHP erforderlich
 ●   Unsicher (PHP!)
 ●   Umständlich
 ●   Inkonsistent

"We hand themers a loaded gun and
 tell them to hammer in a nail with it
 Oh, and be careful" - John Albin


 Wer will denn so etwas wirklich:
 <ul class="views-summary">
   <?php foreach ($rows as $id => $row): ?>
     <li><a href="<?php print $row->url; ?>"<?php print !empty($row_classes[$id]) ? ' class="'. $row_classes
 [$id] .'"' : ''; ?>><?php print $row->link; ?></a>
       <?php if (!empty($options['count'])): ?>
         (<?php print $row->count?>)
       <?php endif; ?>
     </li>
   <?php endforeach; ?>
   </ul>
Zeit für TWIG!
Twig ist eine moderne, schnelle und flexible PHP Template Engine, ganz
zufällig von den Machern von Symfony.
Twig kennt Variablen, Kontrollstrukturen,Vererbung, Funktionen und Filter,
kann gut erweitert werden, bietet Sicherheit und erzeugt schnellen PHP Code.

Beispiel für ein Twig Template:

<!DOCTYPE html>
<html>
<head>
    <title>My Webpage</title>
</head>
<body>
<ul id="navigation">
    {% for item in navigation %}
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor %}
</ul>
<h1>My Webpage</h1>
{{ main_content }}
{% include 'footer.html' %}
</body>
</html>
TWIG für den Drupal Designer
Für den Designer / Themer bedeutet die Einführung von TWIG, dass er es jetzt
anstelle von PHP Templates (.tpl.php) mit TWIG Templates (.twig) zu tun hat.
Dem Themer stehen wie bisher Variablen zur Verfügung, die im Template
verwendet werden können. Statt PHP benötigt er Syntax und Kontroll-
strukturen von TWIG (Anweisungen, Schleifen, Kommentaren, etc.)

region.tpl.php:                         region.twig:

<?php                                   {#
/**                                     /**
 * @file                                 * @file...
 */                                      */
?>                                      #}
<?php if ($content): ?>                 {% if content %}
  <div <?php print $attributes; ?>>     <div {{ attributes }}>
    <?php print $content; ?>               {{ content }}
  </div>                                </div>
<?php endif; ?>                         {% endif %}
Komplexeres Beispiel: comment.twig
{#
/**
 * @file...
 */
#}
<article class="{{ attributes.class }} clearfix" {{ attributes }}>
  {{ render(title_prefix) }}
  {% if new %}
    <mark class="new">{{ new }}</mark>
  {% endif %}
  <h3 {{ title_attributes }}>{{ title }}</h3>
  {{ render(title_suffix) }}

 <footer>
   {{ user_picture }}
   <p class="submitted">by {{ author }} on {{ created }}</p>
   {{ permalink }}
 </footer>

 <div   class="{{ attributes.class }}" {{ attributes }}>
   {#   We hide the links now so that we can render them later. #}
   {#   @TODO uncomment this when http://drupal.org/node/1753676 is resolved
   {%   hide(content.links) %} #}
   {{   render(content) }}

    {% if signature %}
    <div class="user-signature">
      {{ signature }}
    </div>
    {% endif %}
  </div>
  {{ render(content.links) }}
</article>
TWIG für den Drupal Modulentwickler
                         Ganz einfach eigentlich:

          Theming Best Practices beachten!

 ●   Templates explizit registrieren
 ●   Theme-Funktionen in Templates verlagern
 ●   PHP- oder Drupal-Logik in Preprocess-Funktionen verlagern

Warum?
Die Templatesprache ist nicht mehr unbedingt PHP, also haben Templates
möglicherweise keinen Zugriff auf PHP- oder Drupal-Funktionen. Einfache
Kontrollstrukturen können aber vorausgesetzt werden.
Beispiel: TWIG-unfreundliches Modul

Theme-Funktion registrieren:
function mymodule_theme() {
                                                                       Keine Parameter? Also muss
  return array(                                                        die Aufbereitungs- logik im
     'permalink' => array()                                            Theme statt finden!
  );
}

Themefunktion implementieren:
function theme_permalink() {
  $output = '<span class="permalink">';                                Redundanter Code, da ja ein
  if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))) {
    $output .= l(t('Permalink'), 'node/' . arg(1));                    Template gleichen Inhalts
  }                                                                    mitgeliefert wird!
  $output .= '</span>';
  return $output;
}

PHP Template dazu (permalink.tpl.php):
<span class="permalink">
                                                                       Jede Menge PHP- und
<?php if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))): ?>   Drupal-Funktionen, die
  <?php print l(t('Permalink'), 'node/' . arg(1)); ?>                  TWIG normalerweise nicht
<?php endif; ?>
</span>                                                                zur Verfügung stehen!
Besser: TWIG-freundliches Modul

Template registrieren:
function mymodule_theme() {
                                                                     Hier wird explizit ein
  return array(                                                      Template registriert, dem
     'template' => 'permalink',                                      eine Variable übergeben
     'variables' => array('permalink' => NULL),
  );                                                                 wird.
}

Preprocess-Funktion für Programmlogik:
function template_preprocess_permalink(&$variables) {                Hier die Programmlogik zur
  if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))) {
    $variables['permalink'] = l(t('Permalink'), 'node/' . arg(1));   Aufbereitung der Variablen!
  }
}

PHP Template dazu (permalink.tpl.php):
<span class="permalink">                                             Die Templates sind deutlich
<?php print $permalink; ?>                                           einfacher und sehr ähnlich
</span>
                                                                     gehalten, das freut den
TWIG Template dazu (permalink.twig):                                 Themer. Programmlogik und
                                                                     Markup sind getrennt.
<span class="permalink">
{{ permalink }}
</span>
Fragen / Diskussion

Zum Weiterlesen:

http://groups.drupal.org/node/219224
http://drupal.org/sandbox/pixelmord/1750250
http://de.slideshare.net/nyccamp/a-new-theme-layer-for-drupal-8
http://twig.sensiolabs.org



Diese Folien als PDF:

http://www.slideshare.net/drubb

Drupal 8: TWIG Template Engine

  • 1.
    Drupal 8: Twig Template Engine DrupalMeetup Stuttgart 4.10.2012 - drubb
  • 2.
    Was ist eineTemplate Engine? ● Eine Template Engine ersetzt in einer statischen Datei (dem Template) bestimmte Platzhalter durch variable Inhalte, ähnlich einer Seriendruckfunktion. ● Dadurch soll eine Trennung von Programmlogik (z.B. PHP) und Markup (z.B. HTML) erreicht werden - zumindest in der Theorie. Beispiel für ein Template, z.B. als Datei 'kunden.html': <p>Kundenliste</p> <ul> <f:for each="{kunden}" as="eintrag"> <li>{eintrag vorname} {eintrag.nachname}</li> </f:for> </ul> Die Template Engine muss hier nach Platzhaltern suchen und diese durch die eigentlichen Inhalte ersetzen. PHP kann natürlich selbst als Template-Sprache verwendet werden. Beispiel: <h1><?php echo $body_text ; ?></h1> <?php foreach($test_array as $key => $value) : ?> <p>Schlüssel: <?php echo $key; ?> - Wert: <?php echo $value; ?></p> <?php endforeach ; ?> Bekannte Template Engines für PHP sind z.B. Smarty, Fluid (Typo3), PHPTal oder Contemplate.
  • 3.
    Template Engines fürDrupal Drupal 4.5: erste Template Engine XTemplate Drupal 4.7: PHPTemplate als beliebteste Engine Alternative Engines optional auf d.o. verfügbar, z.B. XTemplate, http://drupal.org/project/xtemplate (bis Drupal 4.7) Smarty, http://drupal.org/project/smarty (bis Drupal 6) PHPTAL, http://drupal.org/project/phptal (auch für Drupal 7) PHPTemplate wurde erst in Drupal 7 endgültig Standard. Vorher musste die verwendete Template Engine ausdrücklich im .info File des Themes angegeben werden: name = Garland description = Tableless, recolorable, multi-column, fluid width theme (default). version = VERSION core = 6.x engine = phptemplate stylesheets[all][] = style.css stylesheets[print][] = print.css Zusätzliche Engines konnten (und können nach wie vor) in das Verzeichnis /themes/engines installiert werden, für entsprechende Themes die darauf basieren. Das hat sich aber in der Praxis nicht durchgesetzt.
  • 4.
    Schwachstellen der PHPTemplateEngine ● Drupal-spezifisch ● PHP erforderlich ● Unsicher (PHP!) ● Umständlich ● Inkonsistent "We hand themers a loaded gun and tell them to hammer in a nail with it Oh, and be careful" - John Albin Wer will denn so etwas wirklich: <ul class="views-summary"> <?php foreach ($rows as $id => $row): ?> <li><a href="<?php print $row->url; ?>"<?php print !empty($row_classes[$id]) ? ' class="'. $row_classes [$id] .'"' : ''; ?>><?php print $row->link; ?></a> <?php if (!empty($options['count'])): ?> (<?php print $row->count?>) <?php endif; ?> </li> <?php endforeach; ?> </ul>
  • 5.
    Zeit für TWIG! Twigist eine moderne, schnelle und flexible PHP Template Engine, ganz zufällig von den Machern von Symfony. Twig kennt Variablen, Kontrollstrukturen,Vererbung, Funktionen und Filter, kann gut erweitert werden, bietet Sicherheit und erzeugt schnellen PHP Code. Beispiel für ein Twig Template: <!DOCTYPE html> <html> <head> <title>My Webpage</title> </head> <body> <ul id="navigation"> {% for item in navigation %} <li><a href="{{ item.href }}">{{ item.caption }}</a></li> {% endfor %} </ul> <h1>My Webpage</h1> {{ main_content }} {% include 'footer.html' %} </body> </html>
  • 6.
    TWIG für denDrupal Designer Für den Designer / Themer bedeutet die Einführung von TWIG, dass er es jetzt anstelle von PHP Templates (.tpl.php) mit TWIG Templates (.twig) zu tun hat. Dem Themer stehen wie bisher Variablen zur Verfügung, die im Template verwendet werden können. Statt PHP benötigt er Syntax und Kontroll- strukturen von TWIG (Anweisungen, Schleifen, Kommentaren, etc.) region.tpl.php: region.twig: <?php {# /** /** * @file * @file... */ */ ?> #} <?php if ($content): ?> {% if content %} <div <?php print $attributes; ?>> <div {{ attributes }}> <?php print $content; ?> {{ content }} </div> </div> <?php endif; ?> {% endif %}
  • 7.
    Komplexeres Beispiel: comment.twig {# /** * @file... */ #} <article class="{{ attributes.class }} clearfix" {{ attributes }}> {{ render(title_prefix) }} {% if new %} <mark class="new">{{ new }}</mark> {% endif %} <h3 {{ title_attributes }}>{{ title }}</h3> {{ render(title_suffix) }} <footer> {{ user_picture }} <p class="submitted">by {{ author }} on {{ created }}</p> {{ permalink }} </footer> <div class="{{ attributes.class }}" {{ attributes }}> {# We hide the links now so that we can render them later. #} {# @TODO uncomment this when http://drupal.org/node/1753676 is resolved {% hide(content.links) %} #} {{ render(content) }} {% if signature %} <div class="user-signature"> {{ signature }} </div> {% endif %} </div> {{ render(content.links) }} </article>
  • 8.
    TWIG für denDrupal Modulentwickler Ganz einfach eigentlich: Theming Best Practices beachten! ● Templates explizit registrieren ● Theme-Funktionen in Templates verlagern ● PHP- oder Drupal-Logik in Preprocess-Funktionen verlagern Warum? Die Templatesprache ist nicht mehr unbedingt PHP, also haben Templates möglicherweise keinen Zugriff auf PHP- oder Drupal-Funktionen. Einfache Kontrollstrukturen können aber vorausgesetzt werden.
  • 9.
    Beispiel: TWIG-unfreundliches Modul Theme-Funktionregistrieren: function mymodule_theme() { Keine Parameter? Also muss return array( die Aufbereitungs- logik im 'permalink' => array() Theme statt finden! ); } Themefunktion implementieren: function theme_permalink() { $output = '<span class="permalink">'; Redundanter Code, da ja ein if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))) { $output .= l(t('Permalink'), 'node/' . arg(1)); Template gleichen Inhalts } mitgeliefert wird! $output .= '</span>'; return $output; } PHP Template dazu (permalink.tpl.php): <span class="permalink"> Jede Menge PHP- und <?php if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))): ?> Drupal-Funktionen, die <?php print l(t('Permalink'), 'node/' . arg(1)); ?> TWIG normalerweise nicht <?php endif; ?> </span> zur Verfügung stehen!
  • 10.
    Besser: TWIG-freundliches Modul Templateregistrieren: function mymodule_theme() { Hier wird explizit ein return array( Template registriert, dem 'template' => 'permalink', eine Variable übergeben 'variables' => array('permalink' => NULL), ); wird. } Preprocess-Funktion für Programmlogik: function template_preprocess_permalink(&$variables) { Hier die Programmlogik zur if ((arg(0)=='node') && (is_numeric(arg(1))) && (!arg(2))) { $variables['permalink'] = l(t('Permalink'), 'node/' . arg(1)); Aufbereitung der Variablen! } } PHP Template dazu (permalink.tpl.php): <span class="permalink"> Die Templates sind deutlich <?php print $permalink; ?> einfacher und sehr ähnlich </span> gehalten, das freut den TWIG Template dazu (permalink.twig): Themer. Programmlogik und Markup sind getrennt. <span class="permalink"> {{ permalink }} </span>
  • 11.
    Fragen / Diskussion ZumWeiterlesen: http://groups.drupal.org/node/219224 http://drupal.org/sandbox/pixelmord/1750250 http://de.slideshare.net/nyccamp/a-new-theme-layer-for-drupal-8 http://twig.sensiolabs.org Diese Folien als PDF: http://www.slideshare.net/drubb