Klassen-Konstante von außerhalb der Klasse auslesen

Hin und wieder komme ich in die Verlegenheit außerhalb einer Klasse eine ihrer Konstante verwenden zu wollen oder zu müssen. Auf direkten Weg, also z.B. mit Foo:CONSTANT geht es nicht. Mit der folgenden Methode geht es jedoch wunderbar:

<?php
class Foo
{
const BAR = 'Hallo';
const BAZ = 'Welt!';

/**
*
* Returns the value of a class constant
* @param string $const Name of the constant
* @param string $class [optional] Name of the class (if not set, the constant will be searched in this class)
* @return mixed|false The value of the constant or false if it does not exists
*/
public static function get_constant( $const = '', $class_name = __CLASS__ ){

if( empty( $const ) || ! is_string( $const ) || ! class_exists( $class_name ) )
return FALSE;

$reflection = new ReflectionClass( $class_name );

return $reflection->getConstant( $const );

}

}

class Bar
{
const FOO = 'Horst';
}

$consts = array( 'BAR', 'BAZ', 'FOO' );
foreach( $consts as $const )
var_dump( Foo::get_constant( $const ) );

var_dump( Foo::get_constant( 'FOO', 'Bar' ) );

var_dump( Foo::get_constant( 'TEST', 'Baz' ) );


Gummi-Thickbox

Will man im Backend von WordPress die Thickbox verwenden, bekommt man ein Problem. Zumindest dann, wenn man mit der vorgegebenen Größe nicht einverstanden ist. Die wird nämlich von WordPress mittels eines Scriptes vorgegeben. Bindet man zusätzlich den Editor ein, wird es richtig haarig. Denn im media-upload.js steht dummerweise die Zeile $('a.thickbox').each( function() {...}
Also alle Links mit der Klasse thickbox werden manipuliert. Würde man die Klasse thickbox weg lassen, würde der Link keine Thickbox öffnen. Blöde Situation das ganze.

Ich suchte eine Möglichkeit wie ich die Thickbox in ihrer Größe ändern kann, darüber hinaus mir aber keine Gedanken mehr machen muss wie groß ich sie dimensionieren soll. Die Thickbox sollte sich in ihrer Größe immer schön am dargestellten Inhalt ausrichten. Nach etlichen rumprobieren und etwas suchen, kam ich dann auf folgende Lösung:

jQuery(document).ready(
function($){

resize_thickbox_iframe();
/*
*
* some other jQuery code
*
*/

function resize_thickbox_iframe(){

//padding
var pad = 50;

// give the body a height
$( 'body' ).css( 'height', 'auto' );

// read the bodys height and add some padding
var mh = parseInt( $( 'body' ).height() ) + pad;

var max_height = mh + 'px';

// get the parent window dimensions
var parent = $( window.parent.document );
var ph = parent.height();

// get the ID of this iframe and the iframe itself
frame_id = frameElement.id;
frame = $( '#'+frame_id, window.parent.document );

// get the id of the overlay-div and the overlay-div itself
div_id = frame.parent().attr( 'id' );
div = $( '#'+div_id, window.parent.document );

// first set the hight for the frame, than set the hight for the overlay-div
frame.css( 'height', max_height );
div.css( 'height', max_height );

// calculate the new top position
var tb = Math.round( ( ( ph - mh ) / 2 ) - pad ) + 'px';

// set the new top position
frame.css( 'top', tb );
div.css( 'top', tb );

}

}
);

Das Script setzt die Höhe des body-Tags im iFrame zuerst auf ‘auto’ damit dieser eine Höhe bekommt (für den Fall das der body-Tag noch keine Höhe besitzt). Danach wird das iFrame aus dem Eltern-Dokument gefischt und seine Höhe angepasst. Da sich das iFrame allerdings innerhalb eines Overlay-Divs befindet, muss dieser ebenfalls aus dem DOM gefischt und angepasst werden. Zum Schluss werden Overlay-Div und iFrame neu ausgerichtet.

Das Script gehört in das iFrame hinein! Dementsprechend muss im iFrame auch noch jQuery geladen werden. Wer im iFrame auf jQuery verzichten kann, muss sihc die Funktion auf pures JavaScript umschreiben (ist auch nicht sooo schwer).


Templating mit WordPress

Mit diesen Artikel möchte ich zum Teil ein über 6 Monate altes Versprechen einlösen. Zum anderen ist es der dritte Teil einer Reihe von Beiträgen die Schritt für Schritt zu einer einfachen Template-Engine führen.

Im ersten Teil hatte ich einen Formatter vorgestellt mit dem ich auf vergleichsweise einfache und flexible Art aus Daten eine Ausgabe machen kann. Im zweiten Teil habe ich mittels der Formatter-Klasse und einer Templates-Klasse eine Mini-Template-Engine gebastelt. Die hat aber noch etliche Nachteile und diente lediglich der Darstellung des Prinzips das dahinter steckt.
Diesmal möchte ich auf eine konkrete Implementierung in WordPress eingehen die in dieser Form immer wieder verwendet werden kann. Weiter lesen »


WordPress und FTP

Es gibt einige Möglichkeiten wie man seine FTP-Zugangsdaten an WordPress übermitteln kann. Aus einer kleinen Diskussion auf Google+ heraus kam die Idee diese mal mit ihren Vor- und Nachteilen zusammen zu fassen. Dies will ich im folgenden mal versuchen und dabei versuchen auch die Gründe aufzuzeigen warum WordPress manchmal FTP-Daten braucht und manchmal nicht. Nebenbei ist noch ein kleines Plugin entstanden welches eine weitere Möglichkeit bietet seine FTP-Daten in seien Blog zu hinterlegen. Weiter lesen »


Trenne Ausgabe und Logik

Die Trennung von Ausgabe und Logik ist ein Grundsatz den man beherzigen sollte. Viele CMS bieten Template-Engines an um dies zu erreichen. WordPress bildet in diesen Punkt eine Ausnahme. Es bringt keine eigene Template-Engine mit, sondern setzt auf PHP als Template-Engine. Grundsätzlich keine schlechte Idee, denn PHP ist ursprünglich eine Template-Sprache. Aber die Möglichkeiten die PHP bietet führen grundsätzlich dazu das Logik und Ausgabe munter miteinander vermischt werden, was wiederum zu arg unleserlichen und vor allem unflexiblen Code führt.
In diesen Artikel geht es nicht ausschließlich um WordPress. Das hier gezeigte lässt sich aber sehr leicht auf WordPress anpassen und viele WordPress-Themes haben es bitter nötig sich hinter der Fassade auch mal etwas aufzuhübschen.

Ich hatte in meinem letzten Artikel bereits kurz angesprochen das es eine gute Idee ist Logik und Ausgabe voneinander zu trennen. Eins der besten Argumente für die Trennung von Logik und Ausgabe ist wohl das, dass man einmal geschriebenen Code erneut verwenden kann, man spart sich so viel Arbeit. Aber auch die Übersichtlichkeit steigt, was z.B. die Fehlersuche vereinfacht. Und nicht zu Letzt ist es leichter im Team zu arbeiten. So kann sich einer um die Logik kümmern während der andere sich ausschließlich um das Design (Ausgabe) kümmert.

Das hier im Artikel beschriebene dürfte für PHP-Profis nichts neues sein. Für den einen oder anderen meiner Leser (sofern vorhanden ;) ) kann es aber durchaus interessant sein. Fangen wir also mal ganz locker an.

Ran an den Speck

Ziel soll es sein das in der einen Datei ein Template (Vorlage) steht, während in einer anderen Datei dieses Template mit Daten gefüllt wird. Will man die Trennung noch weiter voran treiben, so legt man weitere Dateien an die sich z.B. um die Beschaffung der Daten kümmern oder um die Ausgabe der Daten (HTML, RSS, Druck, usw.).
Wir wollen uns aber mal darauf beschränken ein einfaches  Template mit einem ebenso einfachem Array zu füllen. Bei dem Template soll es sich um eine Liste handeln. In WordPress zum Beispiel ist fast alles eine Liste. Ob nun die Artikel auf der Startseite, die Blogroll, eine Aufzählung der letzten Kommentare, Menüs, usw. Eigentlich besteht WordPress zu gefühlten 90% aus Listen. Listen dürften als Beispiel also ganz brauchbar sein.
Schauen wir uns mal kurz die Anatomie einer Liste in HTML an. Sie besteht im Prinzip aus zwei Teilen. Den äußeren Teil der die Liste definiert und den inneren Teil der die eigentliche Liste darstellt. In HTML gibt es drei native Listentypen: <ol> (Ordered List), <ul> (Unordered List) und <dl> (Defenition List). Da die <dl>-Liste etwas komplexer ist nehmen wir uns mal die <ol>- und <ul>-Listen vor. Als “Ersatz” für die <dl>-Liste möchte ich eine einfache <div>-Liste dazu nehmen. Die <div>-Liste besteht aus einem äußeren Div-Container und <p>-Tags für die Listenelemente.

Nachdem nun klar ist um welche Listen es geht, brauchen wir noch ein paar Daten für die Liste. Die meisten Daten werden uns als Array oder Objekt zur Verfügung gestellt. Wir können ja mal annehmen wir hätten gerade eine Datenbankabfrage gemacht und wollten nun das Ergebnis als Liste darstellen. Der Einfachheit halber begnügen wir uns mit einem eindimensionalen Array das lediglich die Zahlwörter von Eins bis Drei enthält.

Aus Daten wird eine Liste

Das Problem ein Array als Liste darzustellen ist recht einfach zu lösen. Äußeren Teil ausgeben, das Array durchlaufen und den inneren Teil erstellen, inneren Teil in den Äußern Teil einbetten und fertig ist die Liste.

<?php
require_once 'class-formatter.php';

class Lister extends Formatter
{
public function get_list( $data = array() ){

$inner = new stdClass();
$values = new stdClass();

foreach( $data as $key => $value ){

$values->key = $key;
$values->item = $value;

$inner->inner .= self::sprintf( '<li>%item%', $values );
}

return self::sprintf( '<ol>%inner%</ol>', $inner );

}

}

$data = array( 'Eins', 'Zwei', 'Drei' );

$list = new Lister();
echo $list->get_list( $data );

view raw file1.php This Gist is brought to you using Simple Gist Embed.

Um es gleich ordentlich zu machen verwende ich eine Klasse. Diese Klasse erweitert den Formatter den ich bereits vorgestellt habe und erbt dadurch die Methoden printf() und sprintf(). Zu der Verarbeitung der Key-Value-Paare in der Foreach-Schleife komme ich später noch.

Wenn wir jetzt aber anstatt der Ordered List eine Unordered List erstellen wollen, schreiben wir uns eine neue Klasse!? Das wäre ja nicht Sinn der Aktion, wir wollen ja eine flexible Lösung haben.
Es fehlt die Möglichkeit einen Listen-Typ auszuwählen. Was dafür geändert werden muss, sind die Template-Strings mit dem HTML-Code. Die einfachste Methode um die Templates für verschiedene Listen-Typen zu speichern ist ein Array. Wir benötigen also ein Array das zu jeden Listen-Typ (ol, ul und div) zwei Template-Strings speichert (den inneren Teil und den äußeren Teil).

<?php
require_once 'class-formatter.php';

class Lister extends Formatter
{
public $templates = array();

public function __construct(){

$this->templates = $this->get_templates();

}

public function get_templates(){

$this->templates = array(
'ol' => array(
'outer' => "<ol>n%inner%</ol>n",
'inner' => "<li>%item%</li>n"
),

'ul' => array(
'outer' => "<ul>n%inner%</ul>n",
'inner' => "<li>%item%</li>n"
),

'div' => array(
'outer' => "<div>n%inner%</div>n",
'inner' => "<p>%item%</p>n"
),
);

}

public function get_list( $type = '', $data = array() ){

// get templates if not already set
if( empty( $this->templates ) )
$this->get_templates();

// check if the requested list-typ is defined
if( ! in_array( $type, array_keys( $this->templates ) ) )
return FALSE;

// create list
$inner = new stdClass();
$values = new stdClass();

foreach( $data as $key => $value ){

$values->key = $key;
$values->item = $value;

$inner->inner .= self::sprintf( $this->templates[$type]['inner'], $values );
}

return self::sprintf( $this->templates[$type]['outer'], $inner );

}

}

$data = array( 'Eins', 'Zwei', 'Drei' );

$list = new Lister();
echo $list->get_list( 'ol', $data );
echo $list->get_list( 'ul', $data );
echo $list->get_list( 'div', $data );

view raw file1.php This Gist is brought to you using Simple Gist Embed.

Wunderbar. Jetzt können wir ganz einfach durch Angabe eines Listen-Types und eines Arrays eine Liste erzeugen. Das spart uns schon mal viel Arbeit, denn anstatt für jede Liste eine eigene Foreach-Schleife zu schreiben, benutzen wir einfach die Instanz unserer Klasse.
Und wenn wir jetzt der Liste noch eine CSS-Klasse mitgeben wollen, dann schreiben wir uns eine andere Klasse die das kann!? Vielleicht erweitern wir einfach unsere Klasse dahingehend das sie nicht so starr ist.

Noch mehr Flexibilität

Die fest eingebauten Templates sind zu starr für unsere Zwecke, irgendwie müssen die raus aus der Klasse. Zu Anfang habe ich ja schon geschrieben das die Templates in die eine Datei, die Klasse die aus den Templates fertiges HTML macht in eine andere Datei soll. Das die Klasse oben einen Konstruktor hat, hat seinen Sinn. Denn das ist unser nächster Ansatzpunkt.
Wir schieben einfach die Methode get_templates() in eine Template-Klasse und übergeben der Lister-Klasse ein Objekt das aus der Template-Klasse erzeugt wurde. Damit können wir innerhalb der Lister-Klasse auf die Templates zugreifen. Alles klar soweit? Nicht? Einfach das Beispiel anschauen.

<?php
require_once 'class-formatter.php';
require_once 'class-templates.php';

interface Templates
{
public function get_templates();
}

class Lister extends Formatter
{
public $templates_object = NULL;

public $templates = array();

public function __construct( Templates $templates ){

$this->templates_object = &$templates;

$this->get_templates();

}
protected function get_templates(){

if( NULL === $this->templates_object )
throw new Exception( 'No templates defined' );

$this->templates = &$this->templates_object->get_templates();

}

public function get_list( $type = '', $data = array() ){

// get templates if not already set
if( empty( $this->templates ) )
$this->get_templates();

// check if the requested list-typ is defined
if( ! in_array( $type, array_keys( $this->templates ) ) )
return FALSE;

// create list
$inner = new stdClass();
$values = new stdClass();

foreach( $data as $key => $value ){

$values->key = $key;
$values->item = $value;

$inner->inner .= self::sprintf( $this->templates[$type]['inner'], $values );
}

return self::sprintf( $this->templates[$type]['outer'], $inner );

}

}

$data = array( 'Eins', 'Zwei', 'Drei' );

$list = new Lister( new Simple_List_Templates );

echo $list->get_list( 'ol', $data );
echo $list->get_list( 'ul', $data );
echo $list->get_list( 'div', $data );

<?php
class Simple_List_Templates implements Templates
{
public function get_templates(){

return array(
'ol' => array(
'outer' => "<ol>n%inner%</ol>n",
'inner' => "<li>%item%</li>n"
),

'ul' => array(
'outer' => "<ul>n%inner%</ul>n",
'inner' => "<li>%item%</li>n"
),

'div' => array(
'outer' => "<div>n%inner%</div>n",
'inner' => "<p>%item%</p>n"
),
);

}
}

Ich möchte zur Erklärung schnell mal über die Klasse Lister fliegen. Am Anfang sehen wir ein Interface, das hat in sofern seinen Sinn, als dass man damit bestimmte Bedingungen festlegen kann. So wird im Konstruktor der Lister-Klasse festgelegt das ein Objekt übergeben werden muss das aus einer Klasse erstellt wurde die das Interface Template imlementiert. Damit gehen wir sicher, das dass übergebene Objekt über die Methode get_templates() verfügt. Würden wir versuchen ein Objekt zu übergeben das nicht über diese Methode verfügt, sprich nicht das Interface Template implementiert, würden wir beim Aufruf der Methode get_templates() eine Fehlermeldung bekommen. Damit gehen wir zwar nicht sicher das die Template-Klasse uns beim Aufruf der Methode get_templates() auch ein Array mit Templates zurück gibt, es hilft aber unter Umständen sehr bei der Fehlersuche wenn mal wieder etwas nicht funktioniert.
Im  Konstruktor sehen wir das bei der Parameterübergabe darauf gepocht wird das dass übergeben Objekt das Interface Templates implementieren muss. Das übergebene Objekt speichern wir uns in einer Klassen-Variablen damit wir in anderen Methoden ggf. darauf zugreifen können. Zum Schluss holen wir uns noch die heiß begehrten Templates von der Template-Klasse.
Als nächstes sehen wir dann eine get_templates() Methode. Die Methode sollte ja eigentlich ausgelagert werden. Hier steht sie quasi als Wrapper damit man z.B. noch weitere Kontrollen oder ähnliches einbauen kann. Natürlich hätte man auch z.B. in der Methode get_list() direkt auf die gespeicherte Instanz der Template-Klasse zugreifen können. Aber wir wollen uns ja mal angewöhnen gleich von Anfang an vernünftigen Code zu schreiben. Auch in Beispielen.
Über get_list() muss ich hoffentlich keine Worte mehr verlieren. Templates abholen, Variablen ggf. verifizieren und desinfizieren, Liste basteln und ausgeben.

Ein konkretes Beispiel

Im Prinzip sind wir schon fertig und haben alle unsere gesteckten Ziele erreicht. Die Templates (Ausgabe) stehen in der einen Datei, die Verarbeitung der Daten (Logik) in einer anderen. Beides ist sauber voneinander getrennt. Kommen wir noch mal kurz darauf zurück warum das so sinnvoll sein kann.
Nehmen wir einfach mal den Fall das wir relativ viele Templates haben in denen eine Footer definiert ist . Der könnte nach traditionellem HTML in etwa so aussehen:

<div class="footer">
	<p>Copyright © 2001-2012</p>
</div>

Nun kommt unser Kunde der gelesen hat das HTML5 der letzte Schrei ist und er möchte nun seine Webseite auf HTML5 umgestellt haben weil er befürchtet das sie ansonsten morgen nicht mehr erreichbar ist. Dazu müssten auch alle Footer-Bereiche nach HTML5-Footer konvertiert werden. Aus den Code oben müsste also in etwa folgendes werden:

<footer>
	<p>Copyright © 2001-2012</p>
</footer>

Und das dann nicht nur auf einer Seite, sondern auf allen. Und nicht nur die Footer, sondern auch die Bereiche die eine Section, Navigation, Artikel, usw. darstellen. Der richtige Zeitpunkt um eine Reihe böser Flüche los zu werden, denn das bedeutet tagelanges Wühlen in unübersichtlichen Codezeilen.
Nun werfen wir einen Blick auf unsere Template-Klasse. Dort habe ich eine “Div-Liste” definiert mit der man z.B. solche Footer-Bereiche erzeugen kann. Anstatt nun den kompletten Code neu zu schreiben, tauscht man einfach seine Template-Klasse aus. Aus Simple_List_Templates wird dann z.B. HTML5_List_Templates. Das macht die Sache doch erheblich einfacher als in jeder HTML-Datei Änderungen manuell durchzuführen.
Mit etwas Überlegung kommt man dann auch recht schnell darauf das es eine relativ blöde Idee ist die Template-Klasse beim erzeugen der Lister-Klasse fest zu verdrahten. Zu den Problem komme ich in einen anderen Artikel, dort will ich noch mal auf ein paar Feinheiten eingehen. Dann gehe ich auch noch mal auf die Key-Value-Paare in der Foreach-Schleife ein.

Aber wir sehen schon so, dass man mit der Trennung von Ausgabe und Logik für die Zukunft programmiert. Man kann sowohl die Logik als auch die Templates in verschiedenen Projekten erneut verwenden. Zudem sind Änderungen nicht mehr der Weltuntergang weil man unzählige Dateien durchsuchen und kontrollieren muss. Ich hoffe dem einen oder anderen einen kleinen Denkanstoß gegeben zu haben und wünsche viel Spaß beim selber Ausprobieren.