[phpBB Debug] PHP Warning: in file [ROOT]/ext/tas2580/seourls/event/listener.php on line 213: Undefined array key "FORUM_NAME"
Theming mit Templates - REDAXO Forum
Hallo,

Wir haben in letzter Zeit festgestellt, dass die Kommunikation via Slack viel schneller und zielführender ist als ein Beitrag im Forum. Aufgrund der neuen und besseren Möglichkeiten der Kommunikation haben wir uns entschlossen das Forum nur noch als Archiv zur Verfügung zu stellen. Somit bleibt es weiterhin möglich hier nach Lösungen zu suchen. Neue Beiträge können nicht mehr erstellt werden.

Wir empfehlen, für deine Fragen/Probleme Slack zu nutzen. Dort sind viele kompetente Benutzer aktiv und beantworten jegliche Fragen, gerne auch von REDAXO-Anfängern! Slack wird von uns sehr intensiv und meistens "rund um die Uhr" benutzt :-)
Selbst einladen kannst Du dich hier: https://redaxo.org/slack/
Benutzeravatar
runstop64
Beiträge: 369
Registriert: 23. Okt 2012, 21:34
Wohnort: Hamburg
Kontaktdaten: Website Facebook Twitter

Theming mit Templates

31. Okt 2012, 20:55

Hallo,

ich hatte Peter ja letzte Woche schon angekündigt, dass ich versuchen möchte, mich mit dem ein oder anderen Modul oder Addon einzubringen. Bis ich da etwas veröffentlichungsfähiges habe, wird es wohl noch etwas dauern, allerdings habe ich hier etwas anderes, das ich gerne vorstellen möchte und zu dem mich Eure Meinungen oder Tipps interessieren:
Neben Redaxo arbeite ich auch viel mit Drupal. Dabei habe ich das Theming-System von Drupal zu schätzen gelernt. Der HTML-Teil eines Addons wird in einer eigenen Datei ausgelagert. Speichert man in einem vorgesehen Verzeichnis eine bearbeitete Kopie der HTML-Daten ab, wird diese vom Modul automatisch bei der Ausgabe herangezogen.
Das erleichtert ein optisches Update enorm und nachdem ich beim Erneuern der ersten meiner in die Jahre gekommenen Redaxo-Projekte öfter festgestellt habe, dass so ein System einiges erleichtern würde, habe ich eine Klasse geschrieben, die angelehnt an die Art, wie Templates und Module im Addon-Template in der Datenbank bearbeitet werden, das Theming Konzept auf Redaxo überträgt.

Code: Alles auswählen

<?php
/**
 * Klasse zum rendern von Theme-Daten 
 *
 * Die Dateien werden entweder aus der Datenbank, dem 'developer_files'-Ordner oder 
 * dem Addon-Ordner gelesen.
 * Dem Theme wird ein Array mit Werten übergeben, Übergabe entweder als
 * Variable => Wert 
 * oder als 
 * {Platzhalter} => Wert
 *
 * @version 0.2
 * @author Daniel Weitenauer
 */ 
 
class ahoi_Theme
{
    // Flag für PHP Parser, TRUE = ein
    const PARSE_PHP = TRUE;
    
    protected $param = array(); // Die Variablen, die ans Theme übergeben werden
    protected $file;            // Dateiname
    protected $addon;            // Addon, falls vorhanden
    protected $themeData;        // die eingelesenen Daten
        
    public function __construct(array $param, $file, $addon = NULL) 
    {
        $this->setParam($param);
        $this->file = $file; 
        $this->addon = $addon;
        
        // Daten holen
        $this->themeData = $this->getTheme();
    }

    /**
     * Variablen setzen
     *
     * ein Array mit dem Format array( 'Variable' => Wert, '{Platzhalter}' => Wert );
     *
     * @param array    $param    Variablendaten
     */
    public function setParam(array $param) 
    {
        $this->param = $param;
    }

    /**
     * Theme-Datei holen
     *
     * @param string    $file        Dateiname
     * @param string    $addon        Addon-Ordner
     * @param string    $source        Datenquelle bei Addon ('system', 'files', 'addon') 
     * @return string
     */
    protected function getTheme($file = NULL, $addon = NULL, $source = NULL)
    {
        // Voreinstellungen
        if(!$file) $file = $this->file;
        if(!$addon) $addon = $this->addon;

        $themeData = NULL;
        
        // Daten holen
        // Template
        if ((!$source && $themeData=='') || $source=='system')
        {
            $content = self::getTemplate($file, $addon);
            if ($content) $themeData = $content;
        }
        // Developer-Files
        if ((!$source && $themeData=='') || $source=='files') 
        {
            $themeData = self::getFile($file, $addon, TRUE);
        }
        // Addon-Ordner
        if ((!$source && $themeData=='') || $source=='addon') 
        {
            $themeData = self::getFile($file, $addon, FALSE);
        }
        
        // Hinweis ausgeben
        if (!$themeData) echo('File '.($addon? '["'.$addon.'"] "'.$pathInc : '"'.$pathFiles).$file.'" not found.<br/>');
        return "?>\n".$themeData;
    }

    /**
     * Datei öffnen und parsen.
     *
     * @param array        $param    Parameter
     * @param string    $file    Dateiname
     * @param string    $addon    Addon-Ordner
     * @return string    geparste Datei
     */
    public function parseTheme($param = NULL) 
    {
        if (!is_array($param))
        {
            $param += $this->$param;
        }
        $output = $this->themeData;

        // Parsen
        ob_start();
        // Ersetzen von Tags
        foreach($param as $key => $value)
        {
            if(preg_match('%\{.*\}%', $key)) $output = str_replace($key, $value, $output);
        }
        // PHP parsen
        if (PARSE_PHP)
        {
            $replace = extract($param); // Variablen in aktuellen Namespace übernehmen
            eval($output); // PHP ausführen
        }
        $output = ob_get_contents()."\n";
        ob_end_clean();
        
        return $output;
    }
    
    /**
     * Templates in Datenbank schreiben
     *
     * Templates müssen mit ###ID:[Addon-Name#]Template-Name### ausgezeichnet werden
     *
     * @param string    $addon        Addon-Name
     * @param array        $modules    Template-Namen 
     * @param bool        $branding    true, wenn der Addon-Name eingefügt werden soll  
     * @return                        TRUE bei Erfolg
     */
    public static function writeTemplate($file, $addon = NULL, $developer=FALSE)
    {
        global $REX;
        
        // Datei holen
        $content = self::getFile($file, $addon, $developer);
        if (!$content) return FALSE;
        
        // vorhandene Templates auslesen
        $itId = $itName = NULL;
        $it = new rex_sql;
        $it->setQuery('SELECT * FROM rex_template WHERE content LIKE "%###ID:'.($addon? $addon.'#' : '').$file.'###%"');
        foreach($it->getArray() as $i)
        {
          $itId = $i["id"];
          $itName = $i["name"];
        }
        $sql = new rex_sql;
        $sql->setTable('rex_template');
        $sql->setValue('content', addslashes($content));

        // Modul aktualisieren
        if($itId!=NULL && $itName!=NULL)
        {
            $sql->setWhere('id="'.$itId.'"');
            if($sql->update())
            {
                echo rex_info('"'.$itName.'" updated.');
            }
            else
            {
                $REX['ADDON']['installmsg'][$addon] = 'Could not update "'.$itName.'".';
                return FALSE;
            }
        }
        // Modul installieren
        else
        {
            $sql->setValue('name',addslashes(($addon? $addon.' - ' : '').$file));
            if($sql->insert())
            {
                echo rex_info('"'.($addon? $addon.' - ' : '').$file.'" installed.');
            }
            else
            {
                $REX['ADDON']['installmsg'][$addon] = 'Could not install "'.($addon? $addon.' - ' : '').$file.'".';
                return FALSE;
            }
        }
        return TRUE;
    }
    
    /**
     * Template aus Datenbank holen
     *
     * Templates müssen mit ###ID:[Addon#]Template-Name### ausgezeichnet werden
     *
     * @param string    $addon 
     * @param string    $template 
     * @return string                Template-Inhalt
     */
    protected static function getTemplate($template, $addon = NULL)
    {
        $content = NULL;
        
        $sql = new rex_sql;
        $sql->setQuery('SELECT * FROM rex_template WHERE content LIKE "%###ID:'.($addon? $addon.'#' : '').$template.'###%"');
        foreach($sql->getArray() as $i)
        {
          $content = $i["content"];
        }
        return $content;
    }
    
    /**
     * Datei einlesen
     * @param string    $file        Dateiname
     * @param string    $addon        Addon-Ordner
     * @return string
     */
    protected static function getFile($file, $addon = NULL, $developer = FALSE)
    {
        global $REX;
        
        $themeData = NULL;
    
        $path = $addon? $REX['INCLUDE_PATH'].'/addons/'.$addon.'/theme' : ''; // Addon-Ordner
        if ($developer) $path = $REX['INCLUDE_PATH'].'/developer_files/theme'.($addon? '/'.$addon : ''); // der default-Ordner des Addons 'developer'
    
        if (file_exists($path.'/'.$file.'.tpl.php')) 
        {
            $themeData = file_get_contents($path.'/'.$file.'.tpl.php');
        }
        else
        {
            $themeData = '';
        }
        return $themeData;
    }        
} 
?>
Die Klasse sucht zunächst das Template an verschiedenen Orten (Datenbank, default-Ordner des developer-Addons und Addon-Ordner) und liest es ein. Dann wird ein Mini-Tokensystem ausgewertet und evtl. PHP-code geparst. die geparsten Daten werden dann zurückgegeben.
Manches ist noch nicht ganz fertig bearbeitet, etwa der Vorgang, wenn kein Addon mit angegeben wurde.

Was denkt Ihr?
Daniel

Edit 12.11.: die ursprünglich gepostete Version enthielt Fehler im Quelltext, die sind nun korrigiert...
Zuletzt geändert von runstop64 am 12. Nov 2012, 21:38, insgesamt 1-mal geändert.
Viele Grüße,
Daniel


studio-ahoi.de | Referenzen | Friends Of REDAXO

Benutzeravatar
jdlx
Beiträge: 2615
Registriert: 29. Sep 2005, 10:50
Wohnort: Hamburg
Kontaktdaten: Website

Re: Theming mit Templates

31. Okt 2012, 22:38

So richtig klar ist mir nicht worums geht.. mindestens mal der scope: frontend, backend, beides?

HTML von funktions-code zu trennen ist natürlich grundsätzlich klug.. das prob ist imho zum einen die Grenze zu ziehen - sprich wieviel "funktionale" Anteile will man zulassen, auf welchem Wege macht man Ersetzungen, usw. .. und nicht zu letzt: wieviel neue Komplexität/Knohow hievt man damit an Bord.
Eine bekannte Lösung in der Richtung is ja Smarty.. was ich persönlich z.b. wirklich hasse.. ;) zum einen weil es die Grenze (ok, je nach Anwendung) zw. Funktion/Darstellung massiv verwässert, und eben neue Komplexität (das smarty framework selbst, zusätzliches meta-markup, herumgehieve von vars, etc.) hinzufügt.

Eine imho vernünftige Lösung scheinen mir die fragments in Redaxo 5 zu sein.. weil - so weit ichs grad überblicke - schlank & funktionale Anteile in schlichtem PHP..
vg, Jan

Benutzeravatar
runstop64
Beiträge: 369
Registriert: 23. Okt 2012, 21:34
Wohnort: Hamburg
Kontaktdaten: Website Facebook Twitter

Re: Theming mit Templates

1. Nov 2012, 11:48

Ja, da hast du wohl recht. Bei der Frage des Einsatzgebietes bin ich mir noch nicht hundertprozentig sicher, daher fand ich fertige Template-Systeme auch eher überdimensioniert. Bei der Code-Trennung tendiere ich eher dazu, zwischen standardisiertem und Site-spezifischem Code zu trennen.
Ich habe für unser Büro eine Art Framework für Standardausgaben erstellt, damit lässt sich die meisten anfallenden Gestaltungsaufgaben leicht erledigen. Wenn allerdings eine Ausgabe noch mal in einen zusätzliches DIV gepackt werden soll oder eine Variable überprüft oder umformatiert werden muss, musste das bisher immer im Code passieren. Da leidet auf Dauer die Wartbarkeit und Updatehfähigkeit.
Ich probiere gerade mit der Möglichkeit herum, Templates auf abstraktem Weg, also ohne die ID zu kennen einzubinden, eben auch um mit vorgefertigeten Bausteinen arbeiten zu können, ohne extra etwa die REX_TEMPLATE Aufrufe anpassen zu müssen.
Grundsätzlich muss ich aber erst mal sehen, was die Umwege mit der Performance machen. Es ist auch ein Test, was alles mit Redaxo möglich ist.
Eventuell ist das Ganze für Redaxo 5 ja tatsächlich wieder hinfällig, allerdings hab ich mir die neue Version noch nicht so genau angeschaut.
D
Viele Grüße,
Daniel


studio-ahoi.de | Referenzen | Friends Of REDAXO

Benutzeravatar
cukabeka
Beiträge: 821
Registriert: 31. Mai 2006, 00:01
Wohnort: Aschaffenburg

Re: Theming mit Templates

3. Nov 2012, 20:02

Hallo Daniel,

danke, Dein ansatz klingt interessant, aber so richtig habe ich das auch noch nicht verstanden. Und was kann ich mit der Klasse konkret machen?
Viele Grüße
cukabeka

Benutzeravatar
runstop64
Beiträge: 369
Registriert: 23. Okt 2012, 21:34
Wohnort: Hamburg
Kontaktdaten: Website Facebook Twitter

Re: Theming mit Templates

4. Nov 2012, 14:46

Hallo cukabeka,

momentan hab ich nicht so viel Zeit, aber ich werde die nächsten Tage nochmal versuchen, eine kurze Doku oder ein Beispiel zu schreiben, um die Klasse noch etwas besser zu erklären.
Die Ursprungsidee war, eine Möglichkeit zu schaffen, die Ausgabe eines Addons zu verändern, ohne dass an den Originaldateien gearbeitet werden muss. Damit wäre es z.B. möglich, für angepasste Addons mit Hirbods Installer ein Update durchzuführen (falls nötig), ohne dass Sitespezifische Änderungen überschrieben werden.
Im Prinzip kann man die Klasse immer dann einsetzen, wenn man auf einfache Weise allgemeinen wiederverwendbaren Code mit sitespezifischem kombinieren will, oder wenn man Redaxo-Templates aufrufen möchte, deren ID man nicht kennt, weil sie z.B. automatisch installiert wurden oder wenn man Teile das Codes über das Redaxo-Backend ereichbar machen möchte, ohne dass es gleich Zugriff auf den kompletten Code gibt. Zur Sicherheit könnte dafür auch die PHP Ausführung entfernt werden.
Viele Grüße,
Daniel


studio-ahoi.de | Referenzen | Friends Of REDAXO

Benutzeravatar
cukabeka
Beiträge: 821
Registriert: 31. Mai 2006, 00:01
Wohnort: Aschaffenburg

Re: Theming mit Templates

4. Nov 2012, 15:36

ahoi runstop,

das klingt interessant, danke! bin gespannt auf das beispiel, um das besser zu verstehen. ich habe immer wieder das problem, dass ich teils selbstgeschriebene addons oder templates habe, die ich in mehreren projekten verwende, bei denen ich aber mitunter mit der zeit den überblick verlieren könnte, welche auf welchem versionsstand sind. möglicherweise hilft deine klasse da ja.
Viele Grüße
cukabeka

Benutzeravatar
jdlx
Beiträge: 2615
Registriert: 29. Sep 2005, 10:50
Wohnort: Hamburg
Kontaktdaten: Website

Re: Theming mit Templates

4. Nov 2012, 23:17

cukabeka hat geschrieben:..ich habe immer wieder das problem, dass ich teils selbstgeschriebene addons oder templates habe, die ich in mehreren projekten verwende, bei denen ich aber mitunter mit der zeit den überblick verlieren könnte, welche auf welchem versionsstand sind..
Was du suchst ist eine vernünftige Versionierung ;)
vg, Jan

Benutzeravatar
jdlx
Beiträge: 2615
Registriert: 29. Sep 2005, 10:50
Wohnort: Hamburg
Kontaktdaten: Website

Re: Theming mit Templates

4. Nov 2012, 23:36

runstop64 hat geschrieben:Die Ursprungsidee war, eine Möglichkeit zu schaffen, die Ausgabe eines Addons zu verändern, ohne dass an den Originaldateien gearbeitet werden muss.
Das würde allerdings voraussetzen, daß sämtlicher backend Code, sprich alle Addons (und der core am besten auch) in so eine MVC Richtung umgecodet würden.. spätestens das - so vernünftig die Grundidee auch sein mag - dürfte der dealbreaker sein.
vg, Jan

Benutzeravatar
runstop64
Beiträge: 369
Registriert: 23. Okt 2012, 21:34
Wohnort: Hamburg
Kontaktdaten: Website Facebook Twitter

Re: Theming mit Templates

12. Nov 2012, 22:13

jdlx hat geschrieben:Das würde allerdings voraussetzen, daß sämtlicher backend Code, sprich alle Addons (und der core am besten auch) in so eine MVC Richtung umgecodet würden.. spätestens das - so vernünftig die Grundidee auch sein mag - dürfte der dealbreaker sein.
Sorry, da haben wir uns vielleicht missverstanden. Ich will nicht gleich das ganze Ausgabe-Konzept von Redaxo ändern. Bei uns in der Agentur sind nicht alle Designer gleich fit in PHP, kennen sich aber gut mit HTML aus. Wir experimentieren daher mit den Möglichkeiten, ihnen zu erlauben, eigenständig kleine Ausgabe-Anpassungen vorzunehmen, ohne dass der Entwickler gleich an den Code muss. Die Klasse ist eher als ein erweitertes include() gedacht für Addons bei denen es sinnvoll ist, dem Nutzer zu erlauben, bei gleichbleibenden Funktionen die Frontend-Ausgabe anzupassen, z.B. bei einer verschachtelten Galerie-Ausgabe.
Viele Grüße,
Daniel


studio-ahoi.de | Referenzen | Friends Of REDAXO

Benutzeravatar
runstop64
Beiträge: 369
Registriert: 23. Okt 2012, 21:34
Wohnort: Hamburg
Kontaktdaten: Website Facebook Twitter

Re: Theming mit Templates

12. Nov 2012, 22:13

Hi,
bin leider nicht früher dazu gekommen, doch jetzt habe ich mal eine kurze Zusammenfassung der Methoden geschrieben (dabei musste ich leider feststellen, dass die ursprünglich gepostete Version Fehler enthielt, die habe ich im Anfangspost korrigiert):

Theme-Template erstellen

Code: Alles auswählen

$theme = new ahoi_Theme(array $param, $file, $addon = NULL);
Theme-Template einlesen und Werte übergeben. Führt ->setParam zum Speichern der Übergabewerte aus.

$param
Array mit den Übergabewerten. Die Werte können entweder als Platzhalter in der Form
'{Platzhalter}' => Wert oder als PHP-Variablennamen in der Form 'Variablenname' => Wert übergeben werden.
$file
Als Dateiname ist die Form dateiname.tpl.php vorgesehen. Hier wird nur dateiname ohne .tpl.php übergeben.
$addon
Wenn das Template in einem Addon-Ordner liegt, muss hier der Name des Addon-Folders übergeben werden.

öffentliche Methoden

Code: Alles auswählen

$theme->setParam(array $param);
Übergabewerte speichern.
$param
Array mit den Übergabewerten. (s.o.)

Code: Alles auswählen

$output = $theme->parseTheme($param = NULL);
Die Platzhalter im Theme werden ersetzt. ist die Konstante PARSE_PHP = TRUE werden eventuelle Variablenwerte übergeben und das Template an den PHP-Parser per eval() übergeben.
$param
Bei Bedarf können hier weitere Werte übergeben werden.

Code: Alles auswählen

$flag = ahoi_Theme::writeTemplate($file, $addon = NULL);
Schreibt eine Datei als Template in die Datenbank. Wenn ein Template mit der gleichen Kennung existiert, wird es überschrieben. Diese Methode ist zu großen Teilen aus dem Addon-Template entnommen.
$file
Der Dateiname des Templates (s.o.)
$addon
der Addon-Ordner (s.o.)

Rückgabe TRUE bei Erfolg, sonst FALSE.


Aufruf:

Code: Alles auswählen

$gallery.= $image->parseTheme( array(
    '{id}' => $id, 
    '{path}' => $REX["HTDOCS_PATH"].'index.php?rex_resize='.$p['imageSize'].'a__'.$i,
    '{lightboxpath}' => $REX["HTDOCS_PATH"].'/files/'.$i,
    '{alt}' => $alt,
)); 
Theme-Template: image.tpl.php

Code: Alles auswählen

<!--###ID:slideshow#image###-->
<a id="slideshow-{id}-link" rel="lightbox[lb{id}]" href="{lightboxpath}">
    <img id="slideshow-{id}-display" src="{path}" alt="{alt}" />
</a>
 
Viele Grüße,
Daniel


studio-ahoi.de | Referenzen | Friends Of REDAXO

Zurück zu „Allgemeines [R4]“