viewsPath = rtrim($viewsPath, '/') . '/'; } public function render($file, $data = []): string { 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 Expection("Error rendering template: " . $e->getMessage()); } } private function compileCode($code): string { $code = $this->compileBlock($code); $code = $this->compileYield($code); $code = $this->compileEchos($code); $code = $this->compilePHP($code); return $code; } 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); } private function compilePHP($code): string { return preg_replace('~\{%\s*(.+?)\s*%}~is', '', $code); } private function compileEchos($code): string { $code = preg_replace('~\{\{\s*(.+?)\s*\}\}~is', '', $code); return preg_replace('~\{\{\{\s*(.+?)\s*\}\}\}~is', '', $code); } private function compileEscapedEchos($code):string { return preg_replace('~\{{{\s*(.+?)\s*}}}~is', '', $code); } /* * * */ 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; } private function compileYield($code): string { foreach($this->blocks as $block => $value) { $code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code); } return preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code); } }