abschluss
This commit is contained in:
156
app/Template/Twig.php
Normal file
156
app/Template/Twig.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
namespace Blog\Template;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Einfache Template-Engine zur Verarbeitung von Twig-ähnlichen Templates.
|
||||
*/
|
||||
class Twig {
|
||||
/**
|
||||
* @var array Enthält die erkannten Template-Blöcke.
|
||||
*/
|
||||
private array $blocks = [];
|
||||
|
||||
/**
|
||||
* @var string Pfad zum Template-Verzeichnis.
|
||||
*/
|
||||
private string $viewsPath;
|
||||
|
||||
/**
|
||||
* @var array Globale Variablen, die in allen Templates verfügbar sind.
|
||||
*/
|
||||
private array $globals = [];
|
||||
|
||||
/**
|
||||
* Konstruktor.
|
||||
*
|
||||
* @param string $viewsPath Pfad zum Template-Verzeichnis.
|
||||
*/
|
||||
public function __construct($viewsPath) {
|
||||
$this->viewsPath = rtrim($viewsPath, '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt globale Variablen für alle Templates.
|
||||
*
|
||||
* @param array $globals Assoziatives Array mit globalen Variablen.
|
||||
*/
|
||||
public function setGlobals(array $globals) {
|
||||
$this->globals = $globals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert ein Template mit den übergebenen Daten.
|
||||
*
|
||||
* @param string $file Name der Template-Datei (ohne Pfad).
|
||||
* @param array $data Assoziatives Array mit Variablen für das Template.
|
||||
* @return string Gerenderter HTML-Code.
|
||||
* @throws Exception Wenn das Template nicht gefunden oder ein Fehler auftritt.
|
||||
*/
|
||||
public function render($file, $data = []): string {
|
||||
$data = array_merge($this->globals, $data);
|
||||
|
||||
try {
|
||||
$code = $this->includeFiles($file);
|
||||
$code = $this->compileCode($code);
|
||||
extract($data, EXTR_SKIP);
|
||||
|
||||
ob_start();
|
||||
eval('?>' . $code);
|
||||
return ob_get_clean();
|
||||
} catch(Exception $e) {
|
||||
throw new Exception("Error rendering template: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wandelt den Template-Code in ausführbaren PHP-Code um.
|
||||
*
|
||||
* @param string $code Der Template-Code.
|
||||
* @return string Kompilierter PHP-Code.
|
||||
*/
|
||||
private function compileCode($code): string {
|
||||
$code = $this->compileBlock($code);
|
||||
$code = $this->compileYield($code);
|
||||
$code = $this->compileEchos($code);
|
||||
$code = $this->compilePHP($code);
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt eingebundene oder erweiterte Templates ein.
|
||||
*
|
||||
* @param string $file Name der Template-Datei.
|
||||
* @return string Template-Code mit eingebundenen Dateien.
|
||||
* @throws Exception Wenn die Datei nicht gefunden wird.
|
||||
*/
|
||||
private function includeFiles($file): string {
|
||||
$filePath = $this->viewsPath . preg_replace("/\.twig$/", "", $file) . ".twig";
|
||||
|
||||
if(!file_exists($filePath)) {
|
||||
throw new Exception("View file not found: {$filePath}");
|
||||
}
|
||||
|
||||
$code = file_get_contents($filePath);
|
||||
preg_match_all('/{% ?(extends|include) ?\'?(.*?)\'? ?%}/i', $code, $matches, PREG_SET_ORDER);
|
||||
|
||||
foreach($matches as $match) {
|
||||
$includedCode = $this->includeFiles($match[2]);
|
||||
$code = str_replace($match[0], $includedCode, $code);
|
||||
}
|
||||
return preg_replace('/{% ?(extends|include) ?\'?(.*?)\'? ?%}/i', '', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wandelt {% ... %} in PHP-Code um.
|
||||
*
|
||||
* @param string $code Der Template-Code.
|
||||
* @return string PHP-Code.
|
||||
*/
|
||||
private function compilePHP($code): string {
|
||||
return preg_replace('~\{%\s*(.+?)\s*%}~is', '<?php $1 ?>', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wandelt {{ ... }} in PHP-Echo-Ausgaben um.
|
||||
*
|
||||
* @param string $code Der Template-Code.
|
||||
* @return string PHP-Code mit Echo-Ausgaben.
|
||||
*/
|
||||
private function compileEchos($code): string {
|
||||
$code = preg_replace('~\{\{\{\s*(.+?)\s*\}\}\}~is', '<?=htmlspecialchars($1, ENT_QUOTES, "UTF-8")?>', $code);
|
||||
return preg_replace('~\{\{\s*(.+?)\s*\}\}~is', '<?=$1?>', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sammelt und entfernt Block-Definitionen aus dem Template.
|
||||
*
|
||||
* @param string $code Der Template-Code.
|
||||
* @return string Template-Code ohne Block-Definitionen.
|
||||
*/
|
||||
private function compileBlock($code): string {
|
||||
preg_match_all('/{% ?block ?(.*?) ?%}(.*?){% ?endblock ?%}/is', $code, $matches, PREG_SET_ORDER);
|
||||
foreach($matches as $match) {
|
||||
if(!isset($this->blocks[$match[1]])) {
|
||||
$this->blocks[$match[1]] = '';
|
||||
}
|
||||
$this->blocks[$match[1]] = str_replace('@parent', $this->blocks[$match[1]], $match[2]);
|
||||
$code = str_replace($match[0], '', $code);
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ersetzt yield-Platzhalter durch Block-Inhalte.
|
||||
*
|
||||
* @param string $code Der Template-Code.
|
||||
* @return string Template-Code mit ersetzten Yields.
|
||||
*/
|
||||
private function compileYield($code): string {
|
||||
foreach($this->blocks as $block => $value) {
|
||||
$code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code);
|
||||
}
|
||||
return preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user