0251 / 590 837 15
info@a-coding-project.de
;

Template Overwriting (CMS)

Derzeit kann man in unserem CMS Html-Elemente in Templates auslagern (nicht zu verwechseln mit Skins, die für die ganze Seite bestimmt sind). Die Templates werden derzeit im Ordner /system/templates gespeichert. In diesem Beitrag werden wir das Modell erweitern. Zum einen gibt es dann auch Templates für Plugins (ähnlich wie bei den Klassen) und ganz besonders: Man kann Templates im Skin überschreiben. Damit kann man vom Skin her das Design komplett selbst bestimmen.

Die Templates werden ab jetzt nicht mehr über den Pfad, sondern über einen Namen geladen.

Templates in Plugins können im Ordner /system/plugins/{pluginname}/templates gespeichert werden. Geladen werden diese über plugin_{pluginname}_{templatename}. Des Weiteren wurden die bisherigen Templates in Unterordnern aufgeteilt. Heißt ein Template nun form_settings wird dieses aus der Datei /system/templates/forms/settings.html geladen. Heißt ein Template control_skinselector wird es aus /system/templates/controls/skinselector.html geladen. Alle anderen kommen aus /system/templates.

In dem Skin-Ordner kann nun in dem neuen templates-Ordner ein solches Template überschrieben werden. Der Aufbau dort ist wie im Standard-Template Ordner. Plugin-Templates werden hier im Unterodner Plugins/{pluginname} gespeichert.

So viel zur Theorie, jetzt kommt die Praxis system/classes/template.php:

<?php

class Template{

private $template = „“;

private $loop_templates = array();

private $template_path = „“;

private $loops = array();

private function read_file($filename){

$code = „“;

if(file_exists($filename)){

$templatefile = fopen($filename, „r“);

while(!feof($templatefile)){

$code = $code.fgets($templatefile, 1024);

}

fclose($templatefile);

}

return $code;

}

private function initialize_loops($template){

preg_match_all(„/{LOOP:([w]+)[^}]*}((s*?.*?)*){/LOOP:\1}/“, $template, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {

$template = str_ireplace($match[0], „<!–LOOP(„.$match[1].„)–>“, $template);

$this->loop_templates[strtoupper($match[1])] = $match[2];

if(!array_key_exists(strtoupper($match[1]), $this->loops)){

$this->loops[strtoupper($match[1])] = array();

}

}

return $template;

}

public function load($template,$root){

$path = $this->getTemplatePath($template,$root);

if(file_exists($path)){

$template = $this->read_file($path);

}

elseif(file_exists($this->template_path.„/“.$template)){

$template = $this->read_file($template_path.„/“.$template);

}

$template = $this->initialize_loops($template);

$this->template = $template;

}

public function getTemplatePath($name,$root){

$res = $root;

$namespaces = split(„_“,strtolower($name));

$skin = SkinController::getCurrentSkinName();

if(sizeOf($namespaces) == 3){

if($namespaces[0] == „plugin“){

if(file_exists($root.„/system/skins/“.$skin.„/templates/plugins/“.$namespaces[1].„/“.$namespaces[2].„.html“)){

$res .= „/system/skins/“.$skin.„/templates/plugins/“.$namespaces[1].„/“.$namespaces[2].„.html“;

}

else{

$res .= „/system/plugins/“.$namespaces[1].„/templates/“.$namespaces[2].„.html“;

}

$imported = true;

}

}

else if(sizeOf($namespaces) == 2){

if($namespaces[0] == „form“){

if(file_exists($root.„/system/skins/“.$skin.„/templates/forms/“.$namespaces[1].„.html“)){

$res .= „/system/skins/“.$skin.„/templates/forms/“.$namespaces[1].„.html“;

}

else{

$res .= „/system/templates/forms/“.$namespaces[1].„.html“;

}

$imported = true;

}

else if($namespaces[0] == „control“){

if(file_exists($root.„/system/skins/“.$skin.„/templates/controls/“.$namespaces[1].„.html“)){

$res .= „/system/skins/“.$skin.„/templates/controls/“.$namespaces[1].„.html“;

}

else{

$res .= „/system/templates/controls/“.$namespaces[1].„.html“;

}

$imported = true;

}

}

if(!$imported){

if(file_exists($root.„/system/skins/“.$skin.„/templates/“.$name.„.html“)){

$res .= „/system/skins/“.$skin.„/templates/“.$name.„.html“;

}

else{

$res .= „/system/templates/“.$name.„.html“;

}

}

return $res;

}

public function assign($type, $field, $value){

$this->template = str_ireplace(‚{‚.strtoupper($type).‚:‘.$field.‚}‘, $value, $this->template);

}

public function assign_var($field, $value){

$this->template = str_ireplace(‚{VAR:‘.$field.‚}‘, $value, $this->template);

}

public function add_loop_item($name){

$res = 0;

$this->loops[strtoupper($name)][] = $this->loop_templates[strtoupper($name)];

$res = count($this->loops[strtoupper($name)]) 1;

return $res;

}

public function assign_loop_var($loop_name, $index, $field, $value){

$this->loops[strtoupper($loop_name)][$index] = str_ireplace(‚{VAR:‘.$field.‚}‘, $value, $this->loops[strtoupper($loop_name)][$index]);

}

public function import($area, $template){

if(file_exists($template)){

$template = $this->read_file($template);

}

elseif(file_exists($this->template_path.„/“.$template)){

$template = $this->read_file($template_path.„/“.$template);

}

$template = $this->initialize_loops($template);

$this->template = str_ireplace(‚{INCLUDE:‘.$area.‚}‘, $template, $this->template);

}

public function getCode(){

foreach($this->loops as $key => $array){

$loop_template = implode(n, $array);

$this->template = str_ireplace(‚<!–LOOP(‚.strtoupper($key).‚)–>‘, $loop_template, $this->template);

}

return $this->template;

}

public function output(){

echo $this->getCode();

}

}

?>

Neu in dieser Klasse ist die Funktion getTemplatePath. Sie liefer den Pfad zrück, den wir bisher immer übergeben haben. Der Parameter root, der in der load und in der getTemplatePath ist, ist der relative Pfad zum Hauptverzeichnis.

Jetzt können wir zum Umbau unser bisher erstellten Templates kommen. Fangen wir mal an mit der user_list. Dafür müssen wir die Datei /admin/includes/user.php bearbeiten:

<h1>Benutzer</h1>

<?PHP

$userlist = new Template();

$userlist->load(„user_list“,„../“);

foreach(User::getAllUser() as $user){

$index = $userlist->add_loop_item(„USERLIST“);

$userlist->assign_loop_var(„USERLIST“, $index, „ID“, $user->id);

$userlist->assign_loop_var(„USERLIST“, $index, „NAME“, $user->name);

$userlist->assign_loop_var(„USERLIST“, $index, „ROLE“, $user->role->name);

}

$userlist->output();

?>

Kommen wir zum neuen Skinselector. Die Datei /system/templates/control_skinselector.html muss nun unter /system/templates/controls/skinselector.html gespeichert sein. Der neue Quellcode für die /system/classes/skinselector.php sieht so aus:

<?PHP

class skinselector extends Control{

public $type = „“;

public function getCode(){

$template = new Template();

$template->load(„control_skinselector“,„..“);

$template->assign_var(„NAME“,$this->name);

$template->assign_var(„SELECTORNAME“,$this->type);

$template->assign_var(„VALUE“,$this->value);

$template->assign_var(„CURRENTSKINNAME“,SkinController::getSkinName($this->value));

$i = 0;

foreach(SkinController::getInstalledSkins() as $skin){

$index = $template->add_loop_item(„SKINS“);

$template->assign_loop_var(„SKINS“, $index, „SELECTORNAME“,$this->type);

$template->assign_loop_var(„SKINS“, $index, „INDEX“, $i);

$template->assign_loop_var(„SKINS“, $index, „SKINID“, $skin->id);

$template->assign_loop_var(„SKINS“, $index, „SKINNAME“, $skin->name);

$i++;

}

return $template->getCode();

}

}

?>

Zu guter letzt kommt heute die Settingsform dran. Das alte Template /system/templates/form_settings.html muss nun /system/templates/forms/settings.html heißen. Die Datei /system/classes/settingsform.php sieht dann so aus:

<?PHP

class SettingsForm{

public $area = „global“;

public $areaType = „global“;

public $role = null;

public $url = „“;

public function display(){

if($_POST[’save‘]){

foreach($_POST as $property=>$value){

if($property != „save“ && $property != „roles“){

setSetting($this->area,$this->areaType,$property,$value,$this->role);

}

}

}

$template = new Template();

$template->load(„form_settings“,„..“);

$roleselector = „<select name=roles onchange=document.location.href='“.$this->url.„&role=‘ + this.options[this.selectedIndex].value;>“;

$roles = $GLOBALS[‚db‘]->ReadRows(„SELECT * FROM {‚dbprefix‘}roles ORDER BY name“);

if($roles){

foreach($roles as $role){

if($this->role == $role->id){

$roleselector .= „<option value=.$role->id. selected=selected>“.$role->name.„</option>“;

}

else{

$roleselector .= „<option value=.$role->id.>“.$role->name.„</option>“;

}

}

}

$roleselector .= „</select>“;

$template->assign_var(„ROLES“,$roleselector);

$template->assign_var(„URL“,$this->url.„&role=“.$this->role);

$sql = „SELECT DISTINCT * FROM {‚dbprefix‘}settings WHERE area = ‚“.$this->area.„‚ AND areaType = ‚“.$this->areaType.„‚ AND activated = 1“;

if($this->role){

$sql .= “ AND role = ‚“.$this->role.„‚“;

if($this->role != 3){

$sql .=“ UNION SELECT DISTINCT * FROM {‚dbprefix‘}settings WHERE area = ‚“.$this->area.„‚ AND areaType = ‚“.$this->areaType.„‚ AND activated = 1 AND role = ‚3‘ AND property NOT IN (SELECT DISTINCT property FROM {‚dbprefix‘}settings WHERE area = ‚“.$this->area.„‚ AND areaType = ‚“.$this->areaType.„‚ AND activated = 1 AND role = ‚“.$this->role.„‚)“;

}

}

$rows = $GLOBALS[‚db‘]->ReadRows($sql);

if($rows){

foreach($rows as $row){

$index = $template->add_loop_item(„SETTINGS“);

$template->assign_loop_var(„SETTINGS“, $index, „PROPERTY“, $row->property);

$template->assign_loop_var(„SETTINGS“, $index, „DESCRIPTION“,$row->description);

$control = new $row->type;

$control->name = $row->property;

$control->value = $row->value;

$template->assign_loop_var(„SETTINGS“, $index, „CONTROL“,$control->getCode());

}

}

$template->output();

}

}

?>

Ist euch eigentlich schon das neue Syntax Highlighting aufgefallen? Wenn ja, was haltet ihr davon?