| Benutzer
Registriert seit: 04.01.2009
Beiträge: 43
| Kleine Themplate Class Hallo,
Ich bin langsam am verzweifeln. Ich habe vor eine Template Class zu schreiben.
Nur scheitert es im Moment ein wenig am Template Parsen. Hierfür habe ich eine Metode schon 3 mal neu geschrieben aber sie wird am ende immer sehr unübersichtlich und Groß. Außerdem entdecke ich immer wieder Bug auf die ich keine Lösung finde.
Wie bei diesem Beispiel: PHP-Code: class TemplateParse
{
public $text;
public $newtext;
private $vars = array();
private $vars_loop = array();
public function HasVars()
{
if((count($this->vars) + count($this->vars_loop)) > 0)
return TRUE;
else
return FALSE;
}
public function Assing($varname, $varvalue)
{
if(is_array($varvalue))
$this->vars_loop[$varname] = $varvalue;
else
$this->vars[$varname] = $varvalue;
}
public function Parse($text = NULL, $logic = TRUE, $special_var_set = array(), $special_loop_var_set = array())
{
$logic_str_begin = '<!--!';
$logic_str_end = '-->';
$logic_str_begin_strlen = strlen($logic_str_begin);
$logic_str_end_strlen = strlen($logic_str_end);
if(is_null($text))
$text = $this->text;
//print_r($this->text);
//Setzte Standartmäsig die Suche auf Alles
$search_logic = $logic_str_begin;
//Setze Startposition für die Suche auf 0
$real_search_position = 0;
$search_position = 0;
//Überchreibe mit den Übergebenen Variablen
$local_vars = array_merge($this->vars, $special_var_set);
$local_vars['{}'] = '{';
$local_loop_vars = array_merge($this->vars_loop, $special_loop_var_set);
$not_first_parse_found = TRUE;
$old_end = 0;
while(TRUE) //Suche solange nach
{ //Logischen Operationen bis es keine mehr gibt
$set_first_text = TRUE;
if($real_search_position < $search_position)
$found_begin_logic_pos = strpos($text, $search_logic, $search_position);
else
$found_begin_logic_pos = strpos($text, $search_logic, $real_search_position);
if($found_begin_logic_pos !== FALSE and $logic) //Wenn Logische Operatoren gefunden wurden bzw.
{ //das suchen Aktiviert ist dann
//finde das Ende dazu und führe sie aus.
//danach lasse den gefundenen Text nochmal Parsen
//über diese function (Recrusiv)
//Suche das Ende für den gefundenen Logischen Operator Anfang
//Hier handelt es sich nur um einen Logischen Operator.
//Er wird noch nicht das Ende dazu gesucht
$found_begin_logic_pos_end = strpos($text, $logic_str_end, $found_begin_logic_pos);
//Wie lang ist der Operator?
$operator_leng = $found_begin_logic_pos_end - $found_begin_logic_pos;
//Hole den Operator:
$operator_begin_str = substr( $text,
$found_begin_logic_pos + $logic_str_begin_strlen,
$operator_leng - $logic_str_begin_strlen);
//Suche die Position des Doppelpunktes im Operator
$operator_colon_pos = strpos($operator_begin_str, ':');
//Hole Part1 des Operator
$operator_begin_part1 = substr($operator_begin_str, 0, $operator_colon_pos);
//Hole Part2 des Operator
$operator_begin_part2 = substr($operator_begin_str, $operator_colon_pos + 1);
//Setze die Position ab der nach dem Ende des Start Operators gesucht wird.
//Dazu rechne die Position des gefundenen Operator Endes des ersten Operators
//mit der länge des endes von Operatoren zusammen
$inoperator_begin_pos = $found_begin_logic_pos_end + $logic_str_end_strlen;
$is_logic_comment = TRUE;
switch($operator_begin_part1)
{
case 'begin': //Wenn der Operator begin ist dann handelt es sich um eine Schleife
//Es muss das end dazu gefunden werden
//Setze den Suchstring zusammen.
$search_logic = $logic_str_begin.'end:'.$operator_begin_part2.$logic_str_end;
break;
case 'switch': //Es handelt sich um eine Switch Case verschachtelung
$search_logic = $logic_str_begin.'endswitch:'.$operator_begin_part2.$logic_str_end;
break;
case 'include': //Es handelt sich um ein Include
$search_logic = FALSE;
$end_pos = $found_begin_logic_pos + strlen($operator_begin_str);
break;
default:
$is_logic_comment = FALSE;
}
//Wenn der erste logische Comment gefunden wurde dann
//gebe den Text davor aus wenn du es nicht schon gemacht hast
if($is_logic_comment && $not_first_parse_found)
{
$this->Parse(substr($text, 0, $found_begin_logic_pos), FALSE, $local_vars);
$not_first_parse_found = FALSE;
}
//Extra teil für include das nur einen Teil hat
if($search_logic !== FALSE)
{
//Suche die Position des Endes:
if(isset($found_end_logic_pos_end))
$old_end = $found_end_logic_pos_end;
$found_end_logic_pos_begin = strpos($text, $search_logic, $inoperator_begin_pos);
$found_end_logic_pos_end = $found_end_logic_pos_begin + strlen($search_logic);
$end_pos = $found_end_logic_pos_begin - $inoperator_begin_pos;
//Schneide den Text zwischen den Operatoren aus:
$operatortext = substr($text, $inoperator_begin_pos, $end_pos);
}
//Führe nun die Anweisung der Operatoren aus:
switch($operator_begin_part1)
{
case 'begin': //Operator Begin. Leite eine Schleife ein
//Wenn der zugehörige Variablen Part ein Array ist
if($old_end < $found_begin_logic_pos)
{
echo @substr($text, $old_end, $found_begin_logic_pos - $old_end);
$this->Parse(@substr($text, $old_end, $found_begin_logic_pos - $old_end), TRUE, $local_vars, $local_loop_vars);
}
if(isset($local_loop_vars[$operator_begin_part2]) and is_array($local_loop_vars[$operator_begin_part2]))
{
//Überprüfe welche Variablen noch eine Schleife beinhalten
$themp_array = array();
foreach($local_loop_vars[$operator_begin_part2][0] as $vararraykey => $vararrayvalue)
{
if(is_array($vararrayvalue))
$themp_array[$vararraykey] = TRUE;
else
$themp_array[$vararraykey] = FALSE;
}
foreach($local_loop_vars[$operator_begin_part2] as $vararray)
{
$param1 = array();
$param2 = array();
foreach($themp_array as $key => $value)
{
if($value == TRUE)
$param2[$key] = $vararray[$key];
else
$param1[$key] = $vararray[$key];
}
$this->Parse($operatortext, TRUE, $param1, $param2); //Start die Metode mit dem Teilpart neu
}
}
else
{
$this->Parse(@substr( $text,
$found_begin_logic_pos,
$found_end_logic_pos_end - $found_begin_logic_pos), FALSE, $local_vars);
}
break;
case 'switch':
if($old_end < $found_begin_logic_pos)
{
$this->Parse( @substr($text, $old_end, $found_begin_logic_pos - $old_end),
TRUE,
$local_vars,
$local_loop_vars);
}
if(isset($local_vars[$operator_begin_part2]))
{
//Suche den Richtigen Case Abschnitt:
$logic_string = $logic_str_begin.'case:'.$operator_begin_part2.':'.$local_vars[$operator_begin_part2].$logic_str_end;
$case_pos = strpos($operatortext, $logic_string);
if($case_pos === FALSE) //Wenn nichts gefunden wurde suche nach dem Default
{
$logic_string = $logic_str_begin.'default:'.$operator_begin_part2.$logic_str_end;
$case_pos = strpos($operatortext, $logic_string);
}
if($case_pos !== FALSE) //Wenn etwas gefunden wurde
{
//Suche den die Break Position:
$logic_string_tmp = $logic_string;
$logic_string = $logic_str_begin.'break:'.$operator_begin_part2.$logic_str_end;
$break_pos = strpos($operatortext, $logic_string, $case_pos + strlen($logic_string_tmp));
if($break_pos === FALSE) //Wenn es kein Break gibt laufe bi zum Schluss durch.
$break_pos = $found_end_logic_pos_begin;
$this->Parse( substr($operatortext, $case_pos, $break_pos - $case_pos),
TRUE,
$local_vars,
$local_loop_vars);
}
//print_r($operatortext);
}
else
{
$this->Parse(@substr( $text,
$found_begin_logic_pos,
$found_end_logic_pos_end - $found_begin_logic_pos), FALSE, $local_vars);
}
//Den Letzten Teile ausgeben um nicht existierende logic Comments einfach auszugeben
break;
case 'include':
if(substr($operator_begin_part2, 0, 1) != '/')
$path = $this->templatedir . '/';
else
$path = '';
if(file_exists($path . $operator_begin_part2))
{
//Datei öffnen
$fh = fopen($path . $operator_begin_part2, 'r');
//Prüfen ob Datei geöffnet
if($fh)
{
//Aus Datei Lesen
$read = fread($fh, filesize($path . $operator_begin_part2));
//Wenn etwas in Datei vorhanden dan Parse es
if(strlen($read) > 0)
$this->Parse($read, TRUE, $local_vars, $local_loop_vars);
//Datei schließen
fclose($fh);
}
}
break;
}
//Setze end Position. Wenn es ein Logisches Comment ist dann wissen wir die Position.
//Wenn nicht dann gehen wir einfach ein Zeichen weiter.
if($is_logic_comment and $search_logic !== FALSE)
{
$real_search_position = $found_end_logic_pos_begin + strlen($search_logic);
}
elseif($search_logic === FALSE) //Kleiner Extra Teil für Include
{
$real_search_position = $found_begin_logic_pos_end + $logic_str_end_strlen;
$found_end_logic_pos_end = $real_search_position;
}
else
{
$search_position++;
}
//Setzte die Suche wieder auf Alles
$search_logic = $logic_str_begin;
}
else //Wenn keine Logischen Operationen mehr vorhanden sind
{ //dann ersätze die Variablen und beende die Metode.
$this->newtext .= strtr(substr($text, $real_search_position), $local_vars);
//echo
return $this->newtext;
}
}
}
}
//
class redTemplate extends TemplateParse
{
private $incachevars = array();
private $cache = NULL;
public $templatedir;
public function __construct($cache = TRUE, $templatedir = 'templates')
{
if(is_object($cache))
$this->cache = $cache;
else
$this->cache = NULL;
$this->templatedir = $templatedir;
}
public function SetVar($varname, $varvalue, $cache = FALSE)
{
if($cache)
$this->Assing($varname, $varvalue);
else
$this->incachevars[$varname] = $varvalue;
}
public function Exists($cat, $template, $cachename1, $cachename2)
{
return $this->Exists(array($cat.'/'.$template, $cachename1, $cachename2));
}
public function Load($cat, $template, $cachename1, $cachename2 = NULL)
{
$parse = TRUE;
if($cachename2 === NULL)
$cachename2 = 0;
if( ( $this->cache !== NULL ) && ($cachename1 !== NULL) && ( $content = $this->cache->Load( array($cat.'/'.$template, $cachename1, $cachename2) ) ) )
{
$parse = FALSE;
}
else //Lade Themplate
{
$path = $this->templatedir.'/'.$cat.'/'.$template;
if(file_exists($path) && is_readable($path))
{
$fh = fopen($path, 'r');
$content = fread($fh, filesize($path));
fclose($fh);
}
else
return FALSE;
}
if($this->HasVars())
$cache_it = TRUE;
else
$cache_it = FALSE;
//Sachen Parsen die im Cache normalerweise vorhanden sind
if($parse)
$content = $this->Parse($content);
if($cache_it && ($this->cache !== NULL) && ($cachename1 !== NULL))
{
$this->cache->Save($content, array($cat.'/'.$template, $cachename1, $cachename2));
}
$this->vars = array();
$this->vars_loop = array();
$this->newtext = '';
foreach($this->incachevars as $varname => $value)
$this->Assing($varname, $value);
$content = $this->Parse($content);
return $content;
}
}
$test = new redTemplate();
$test->SetVar('schleife_im_include', array(
array(
'{variable_in_der_schleife_nummer_1}' => 'Testausgabe fuer die erste Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_1})',
'{variable_in_der_schleife_nummer_2}' => 'Testausgabe fuer die erste Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_2})'),
array(
'{variable_in_der_schleife_nummer_1}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_1})',
'{variable_in_der_schleife_nummer_2}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_2})'),
array(
'{variable_in_der_schleife_nummer_1}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_1})',
'{variable_in_der_schleife_nummer_2}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_2})'),
array(
'{variable_in_der_schleife_nummer_1}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_1})',
'{variable_in_der_schleife_nummer_2}' => 'Testausgabe fuer die zweite Ausgabe (An Stelle der Variable: {variable_in_der_schleife_nummer_2})')
)
);
$test->Load('abc', 'abc', 'afsdf', 'sdf');
dazu: templates/abc/abc Code: Hier wird nun die Datei test_include.html geladen. Sie wird auch geparsed.
<-- Start test_include.html -->
<!--!include:abc/test_include.html-->
<-- End test_include.html -->
<!--!begin:schleife_im_include-->
{variable_in_der_schleife_nummer_1}
{variable_in_der_schleife_nummer_2}
<!--!end:schleife_im_include-->
templates/abc/test_include.html Code: Das ist jetzt in der test_include.html Datei
Und hier hoert die test_include.html Datei auf
Diese Classe Bugfrei zu machen ist denke ich sinnlos.
Ich denke ich mache mir das viel zu Umständlich.
Hat jemand eine Idee wie ich mein Vorgehen vereinfachen kann?
zur Info:
Am Ende sollte die im Template folgendes möglich sein: Code: Eine Schleife:
<!--!begin:variable-->
Schleife blablabla
In der Schleife soll auch geparsed werden können z.b. include
<!--!include:toll.html-->
<!--!end:variable-->
<!--!switch:variable-->
<!--!case:variable:wert1-->
BlaBlaBla
<!--!case:variable:wert2-->
bei wert2 wird das auch noch ausgeführt
<!--!break:variable-->
<!--!default:variable-->
Standart Wert
<!--!endswitch:variable-->
Hat jemand eine Idee?
PS: Ich möchte eigentlich keine fertige Class nutzen da ich:
1. Auch mal wissen will wie man sowas macht.
2. Mir die großen Template Systeme von der Syntax im Template nicht gefallen
3. Mir die großen Systeme zu überdimensioniert sind. Das Template System ist dann größer als das Projekt. |