Allgemein

Smarty

Smarty Template Engine

In diesem Artikel geht es um die Implementierung von Smarty in CodeIgniter – HMVC. Standardgemäß ist die mitgegebene Template-Engine von CodeIgniter nicht sonderlich performant und optimal für die Entwicklung einer CMS mit der Möglichkeit Themes zu strukturieren oder Partials zu verwenden. Spätestens beim Einsatz von HMVC stößt man mit der Standard-Template Engine von CodeIgniter an die Grenzen. Insbesondere sobald die jeweiligen Buttom-Level-Agents geformt werden, scheitert die absolute Modularität daran, dass sich Partials nicht definieren lassen, oder besser gesagt nur bedingt.

 Gründe für Smarty als Template-Engine

Smarty ist eine Template Engine, es schafft eine weitere Abstraktionsebene zu einem gewöhnlichen PHP/HTML-Template, welches sich ebenfalls schöner ließt als PHP in HTML. Die hauptsächlichen Gründe um Smarty aber tatsächlich zu nutzen sind andere. Smarty bietet die Möglichkeit Partials zu definieren und diese elegant zu nutzen. Es gibt als Beispiel die Möglichkeit Captures und Blocks zu definieren.

Blocks sind in Smarty wie der Name schon sagt „Blöcke“. Diese Blöcke erhalten jeweils Namen und können über diese Namen identifiziert werden. Somit ist es Beispielsweise möglich, über verschiedene Templates die z.B. in den View-Verzeichnissen von Modulen hinterlegt werden, bestehende Templates zu erweitern oder Teile davon zu überschreiben. Dies geht dadurch, dass Smarty die Möglichkeit bietet Blöcke zu Prependen, Appenden oder zu Überschreiben.

Ebenfalls durch das definieren von Captures ist es möglich Template-Blöcke zu definieren, welche evtl. sogar Blöcke beinhalten die während der Laufzeit des jeweiligen Frameworks (in unserem Falle CI) erweitert werden. Anschließend lassen sich diese Captures innerhalb von  anderen Templates nutzen und an bestimmte Positionen in einem Grundgerüst includen.

 

 Installation von Smarty in CI

Das Aufsetzen von Smarty in CI (HMVC) ist recht simpel. Hierfür ist es größtenteils nicht mehr notwendig eigenen Sourcecode dafür zu entwickeln, denn auch für CodeIgniter gibt es eine Erweiterung um Smarty zu implementieren.

Dazu ist es allerdings notwendig folgende Erweiterung herunterzuladen und in die entsprechenden CI-Verzeichnisse zu kopieren. Allerdings muss man dafür eingestehen, dass diese Library nicht sonderlich gut bis gar nicht dokumentiert ist. Das mag in erster Linie abschreckend sein, allerdings sei gesagt, dass diese Erweiterung trotzdem recht simpel zu bedienen ist.

Anschließend muss die Smarty-Library der Autoloader-Konfiguration für Libraries als Eintrag mitgegeben werden. Dazu wird in der Datei /application/config/autoload.php der Eintrag

$autoload['libraries'] = array('parser');

mitgegeben. Ebenfalls benötigt diese Library als Autoload auch den URL-Helper. Dementsprechend muss auch dieser in der Autoload-Konfiguration mitgegeben werden

$autoload['helper'] = array('url');

 

Hat man die Absicht mit Smarty verschiedene Themes anzulegen, so geht dies recht einfach. Dazu muss ein Verzeichnis „themes“ im Root-Verzeichnis der Anwendung angelegt werden (nicht Application!).

mkdir path/to/codeigniter/themes

Anschließend wird in diesem Ordner ein weiteres Verzeichnis angelegt (Standardgemäß „default“)

mkdir path/to/codeigniter/themes/default

Dieses Verzeichnis muss mind. drei Ordner beinhalten, die dementsprechend auch angelegt werden müssen:

Diese Verzeichnisse dienen für die jeweiligen Ressourcen die von der Applikation für die Views genutzt werden sollen, und über dien Parser-Helper dann eingebunden werden können.

Verwendung von Parser-Helper

Dazu sieht die Syntax wie folgt aus innerhalb der Smarty-Templates um die obigen Ressourcen einzubinden.

Bilder
{image('logo.png')}

Mit diesem Schnipsel wird die Bilddatei „logo.png“ aus dem gerade geladenen Theme aus dem img-Verzeichnis geladen und mit dem entsprechenden Image-Tag im Template eingebunden (Beispiel Url: http://example.com/themes/default/img/logo.png)

Javascript
{js('bootstrap.min.js')}

Hiermit wird das Javascript „bootstrap.min.js“ im Quelltext mit dem entsprechenden Script-Tag eingebunden (Beispiel Url: http://example.com/themes/default/js/bootstrap.min.js)

CSS
{css('bootstrap.min.css')}

Und auch hier ist es das gleiche Spielchen wie mit den beiden anderen Helpern. Auch hier wird das CSS in dem entsprechenden link-Tag eingebunden. (Beispiel Url: http://example.com/themes/default/css/bootstrap.min.css)

Templates anlegen

Für das Anlegen von Templates gibt es verschiedene Verzeichnispfade in denen sich Templates anlegen lassen (Leider sind diese im Github-Repo nicht dokumentiert). Allerdings habe ich selbst vor längerer Zeit diese Pfade mal nachrecherchiert:

Wer Smarty auf seine Bedürfnisse konfigurieren möchte, bzgl. des Default-Themes oder anderen Angelegenheiten kann sich auch an der Konfiguration austoben die sich  unter /application/config/smarty.php befindet.

Wichtig ist, dass das Cache-Verzeichnis bei der Verwendung von Smarty beschreibbar für den Webserver ist. Da Smarty nicht nur die Templates parsed, sondern diese auch kompiliert und die kompilierten Templates im Cache hinterlegt, welche dann aus dem Cache für einen definierten Zeitraum geladen werden können.

Profiling

Auch die Profiling-Klasse von CodeIgniter wird durch die Extension erweitert. Dementsprechend sobald der Profiler enabled wird, werden auch Profiling-Informationen für Smarty ausgegeben, dies geschieht sobald folgender Quellcode in einem Controller definiert wurde:

$this->output->enable_profiler(TRUE);

Beispielhafte Verwendung von Smarty

Auch ein demonstratives Beispiel für die Verwendung von Smarty habe ich vorbereitet.

Dazu legen wir uns in unserem Theme Verzeichnis folgende Struktur an:

 

base.tpl – Inhalt

{capture append="theme_Head"}
    <title>{block name="theme_headtitle"}{$headtitle}{/block}</title>
    {block name="theme_metadata"}
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    {/block}
    {block name="theme_css"}
        {css('bootstrap.css')}
        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
          <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
          <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
    {/block}
    {block name="theme_favicon"}
    <link rel="shortcut icon" href="">
    {/block}
    {block name="theme_metadata_keywords"}    

    {/block}
{/capture}

<html lang="en">
    <head>
      {foreach from=$theme_Head item="_block"}
          {$_block}
      {/foreach}
    </head>
    <body>
        {foreach from=$theme_PageBody item="_block"}
            {$_block}
        {/foreach}

        {block name="theme_js"}
            {js('bootstrap.min.js')}
        {/block}
    </body>
</html>

Hier definieren wir unser Grundgerüst für unser Basis-Template, worin einzelne weitere Templates included werden können, oder die bestehenden Blocks erweitert werden können. Erweiterungen von Blocks erfolgt mittels weiterer Templates mit dem Inhalt:

{extends file="base.tpl"}
{block name="theme_headtitle" append}
Page Title
{/block}

Zu Blocks gibt es weiteres mehr auf der Smarty-Dokumentationsseite.

welcome_message.tpl – Inhalt

{capture append="theme_PageBody"}
<div id="container">
    <h1>{$title}</h1>
    <div id="body">
            <p>The page you are looking at is being generated dynamically by CodeIgniter.</p>

            <p>If you would like to edit this page you'll find it located at:</p>
            <code>application/views/welcome_message.php</code>

            <p>The corresponding controller for this page is found at:</p>
            <code>application/controllers/welcome.php</code>
    </div>
    <p class="footer"></p>
</div>
{/capture}
{include file="layout/base.tpl"}

Hierbei erweitern wir das Capture aus der Base.tpl, und durch das nachladen der Base.tpl am Ende des Captures erzwingen wir die Base.tpl dazu, das Capture anzuzeigen.

Welcome-Controller

Somit könnten wir unseren Controller wie folgt definieren, um das komplette Template welches wir definiert haben anzuzeigen, sobald das welcome_message.tpl als View geladen wird:

class Welcome extends Frontend_Public{

    protected $_sViewName = "page/welcome/welcome_message.tpl";

    public function __construct() {
        parent::__construct();
        $this->output->enable_profiler(TRUE);
    }

    public function index(){
        $data = array();
        $data["headtitle"] = "My Little Smarty";
        $data["title"] = "Welcome to CodeIgniter!";
        $this->parser->parse($_sViewName, $data);
    }
}