Hallo und Herzlich willkommen zum dritten Teil der „Das eigene kleine Portfolio mit dem Slim Framework, RainTPL & Co.“ Reihe.

Diese Woche möchte ich euch den aktuellen Stand präsentieren. Zur Erinnerung: Folgende Punkte wollte ich seit letzter Woche erledigen…

  • Die RainTPL Wrapper Klasse für das Slim Framework soll entwickelt werden
  • Es gilt eine Klasse zu erstellen, die uns bei der Strukturierung der einzelnen Seiten hilft

Zum ersten Punkt

Die Macher von Slim haben in ihrem „Slim-Extras“ Github Repository bereits einen Wrapper für RainTPL erstellt (habe ich letztes mal wohl übersehen) – Allerdings ist dieser nicht für die RainTPL 3 Beta Version, sondern für Version 2… Bedeutet hier musste zwar ein wenig dran gearbeitet werden, doch der Aufwand hielt sich in Grenzen.
Die Wrapper-Klasse war ursprünglich als Singleton umgesetzt – das musste ich aber ändern, da ich mehrere RainTPL Instanzen benötige um die einzelnen Templates zu rendern.

Zum zweiten Punkt

Ich habe eine kleine Klasse namens „Structure“ erstellt, welcher ich beliebig viele (Template-) Elemente hinzufügen kann. Dazu habe ich die zwei Methoden add($tpl, $data) und add_first($tpl, $data) erstellt – Diese liefern am Ende das eigene Objekt zurück um gleich mehrere Elemente hintereinander zu erstellen (Method Chaining).
Mit Hilfe einer einfachen „render“ Methode lassen sich alle Templates dann der Reihe nach darstellen… Das ganze funktioniert auch über die magische „__toString“ Methode. Die einzelnen Templates werden, meinem Layout entsprechend, durch einzelne <hr /> Elemente getrennt.

Die Klasse selbst implementiert das Iterator interface und ermöglicht es mir somit (auf Wunsch) direkt im Controller mit Hilfe einer foreach-Schleife die einzelnen Elemente zu durchlaufen.

Der Quellcode der Klasse sieht folgendermaßen aus

/**
 * Klasse zum zusammenstellen mehrerer Template-Teile zu einer Struktur.
 * 
 * @uses        RainTPL
 * @author      Leonard Fischer 
 * @copyright   2012 Leonard Fischer
 * @version     1.0.0
 * @package     Portfolio
 */
class Structure implements Iterator
{
    /**
     * Das Struktur Array.
     * @var  array
     */
    public $structure = array();

    /**
     * Die Template klasse.
     * @var  Slim\Extras\Views\Rain
     */
    protected $tpl;

    /**
     * Erstellt ein neues Struktur Element.
     *
     * @param   string  $tpl
     * @param   array   $data
     * @return  Structure
     */
    public function add ($tpl, array $data = array())
    {
        $this->structure[] = array(
            'tpl' => $tpl,
            'data' => $data
        );

        return $this;
    }

    /**
     * Setzt ein Element an den Anfang.
     *
     * @param   string  $tpl
     * @param   array   $data
     * @return  Structure
     */
    public function add_first ($tpl, array $data = array())
    {
        $this->structure = array_reverse($this->structure);
        $this->add($tpl, $data);
        $this->structure = array_reverse($this->structure);

        return $this;
    }

    /**
     * Statische factory Methode zum unterstützen des Method-Chaining.
     *
     * @param   \Slim\Extras\Views\Rain  $tpl
     * @return  Structure
     */
    public static function factory ($tpl)
    {
        return new self($tpl);
    }

    /**
     * Gibt die Struktur fertig gerendert zurück.
     *
     * @param   boolean  $to_string
     * @return  string
     */
    public function render ($to_string = true)
    {
        $return = array();

        foreach ($this->structure as $structure)
        {
            $this->tpl->setData($structure['data']);

            $return[] = $this->tpl->render($structure['tpl']);
        }

        if ($to_string === true)
        {
            return implode("<hr />", $return);
        }

        echo implode("<hr />", $return);
    }

    /**
     * Konstruktor.
     *
     * @param  \Slim\Extras\Views\Rain  $tpl
     */
    public function __construct ($tpl)
    {
        $this->tpl = $tpl;
    }

    /**
     * Magische "__toString" Methode, ruft intern "render()" auf.
     *
     * @return  string
     */
    public function __toString()
    {
        return $this->render();
    }


    /* Weitere Methoden vom "Iterator" Interface... */
}

Unser Quelltext in der index.php hat sich durch diese und die RainTPL Wrapper Klasse folgendermaßen geändert…

// Start RainTPL and Slim framework.
$app = new Slim(array(
    // Application
    'mode' => 'development',
    'view' => new \Slim\Extras\Views\Rain(array(
        'base_url' => null,
        'tpl_dir' => 'tpl/',
        'cache_dir' => 'tmp/'
    )),
    // Debugging
    'debug' => true,
));

$app->view()
    ->register_tag('({i18n=".*?"})', '{i18n="(.*?)"}', function ($params) {
        echo 'Translate something.';
    });

// Routen definieren.
$app->get('/', function () use ($app) {
    $structure = Structure::factory($app->view())
        ->add('text', array(
            'headline' => 'Hey there',
            'paragraphs' => array(
               'My name is Leonard Fischer, and I\'m a web developer ' /* ... */ ,
               'I mainly work with the PHP Framework ' /* ... */ ,
            )))
        ->add('bars', array(
            'headline' => 'Skils',
            'items' => array(
                array(
                    'headline' => 'PHP',
                    'class' => 'twocol',
                    'bars' => array(
                        'PHP5' => 100,
                        'Kohana' => 100,
                        'ProcessWire' => 75,
                        /* ... */
                    )
                ),
                array(
                    /* ... */
                )
            )));

    $app->render('_base', array('content' => $structure));
});

RainTPL hat sich wirklich sehr angenehm in das Framework einarbeiten lassen! Durch die Wrapper-Klasse ist es nun außerdem möglich einige weitere Anpassungen an der Behandlung von Views und Daten vorzunehmen ohne den eigenen Quelltext von RainTPL oder Slim anzupassen. Das System ist gut durchdacht und macht Spaß zu nutzen!

Leider ist durch die Methoden „factory()„, „initialize()“ und „register_tag()“ die 1:1 Kompatibilität zu anderen Template-Engines (Siehe die anderen Wrapper Klassen im Github Repo) kaputt gegangen – Die Methoden benötigt ich allerdings zwingend!

Das Template

Durch die neuen Strukturen hat sich natürlich auch unser Template etwas verändert… Das „_base“ Template sieht nun folgendermaßen aus:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<title>Leonard Fischer - Web Development</title>
	<link rel="stylesheet/less" type="text/css" href="css/style.less">
	<script src="js/jquery-1.8.2.min.js" type="text/javascript"></script>
	<script src="js/less-1.3.0.min.js" type="text/javascript"></script>
	<script src="js/scripts.js" type="text/javascript"></script>
</head>
<body>
<div class="container">
	<img src="images/logo.gif" id="logo" />

	<div id="contentwrapper">
		{$content}
	</div>
</div>
</body>
</html>

Ein schönes schlankes Template, wie man es sich wünscht… Oder?
Derzeit binden wir nur jQuery, Less und eine eigene Skript-Datei ein, in der wir u.a. hover-effekte für die Gallery-Elemente und das Responsive-Verhalten abhandeln (Mehr dazu nächste Woche).

Die anderen Templates sind ähnlich schlicht gehalten: Das Text-Template (text.html)

<section class="text">
    {if="$headline"}<h1>{$headline}</h1>{/if}
    {loop="$paragraphs"}<p>{$value}</p>{/loop}
</section>

Das Prozentbalken-Template (bars.html)

<section class="bars">
    {if="$headline"}<h2>{$headline}</h2>{/if}
    {loop="$paragraphs"}<p>{$value}</p>{/loop}
    {loop="$items"}
    <div class="{$value.class}">
        {if="$value.headline"}<h3>{$value.headline}</h3>{/if}
        {if="$value.bars"}
        <ul>
            {loop="$value.bars"}
            <li class="bar bar-{$value}"><span>{$key}</span></li>
            {/loop}
        </ul>
        {/if}
    </div>
    {/loop}

    <br class="cb" />
</section>

Das Gallery-Template (gallery.html)

<section class="gallery">
    {if="$headline"}<h2>{$headline}</h2>{/if}
    {loop="$paragraphs"}<p>{$value}</p>{/loop}
    {loop="$images"}
    <div class="threecol" style="background:url('tpl/projects/thumb_{$value.image}');"><div>
        <img src="images/zoom.png" alt="zoom" />{$value.description}
    </div></div>
    {/loop}

    <br class="cb" />
</section>

Das Layout an sich ist gleich geblieben und wird wohl nicht weiter verändert werden. Es sagt mir vielleicht nicht 100%’ig zu, ist aber hervorragend für dieses Tutorial geeignet.

Eine Kleinigkeit noch

Ich plane dieses Projekt auf github veröffentlichen, sobald es den finalen Stand erreicht (und ich rausgefunden habe wie ich fremde Repo’s einbinden kann – Für jQuery, Less, RainTPL und Slim ;)).

Außerdem plane ich für nächste Woche einen Einblick in das CSS und Javascript der Seite – Mit speziellem Fokus auf das Responsive Verhalten. Zusätzlich werde ich noch ein-zwei (Dummy?) Seiten anlegen um zu demonstrieren wie wir mit Slim und der Structure Klasse weitere Inhalte erstellen können.

Mit diesen Worten möchte ich mich verabschieden und hoffe ihr schaut auch nächste Woche rein…
Ich wünsche euch allen das obligatorische Happy Coding!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.