Huymada

Template

Aug 22nd, 2019 (edited)
397
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.95 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Gestor de Templates
  4.  * @version 2.0
  5.  */
  6. class Template {
  7.  
  8.     /**
  9.      * Diretório base dos templates
  10.      */
  11.     private string $dir;
  12.  
  13.     /**
  14.      * Extensão dos arquivos de template
  15.      */
  16.     private string $ext;
  17.  
  18.     /**
  19.      * Cache em memória: ['nome' => 'conteúdo raw']
  20.      */
  21.     private array $cache = [];
  22.  
  23.     // -------------------------------------------------------------------------
  24.  
  25.     /**
  26.      * @param string $dir Diretório dos templates (padrão: 'template/')
  27.      * @param string $ext Extensão dos arquivos    (padrão: '.tpl')
  28.      *
  29.      * @throws RuntimeException se o diretório não existir
  30.      */
  31.     public function __construct(string $dir = 'template', string $ext = '.tpl') {
  32.         if (!is_dir($dir)) {
  33.             throw new RuntimeException(
  34.                 "Template: diretório não encontrado — \"{$dir}\""
  35.             );
  36.         }
  37.  
  38.         $this->dir = rtrim($dir, '/\\');
  39.         $this->ext = '.' . ltrim($ext, '.');
  40.     }
  41.  
  42.     // -------------------------------------------------------------------------
  43.  
  44.     /**
  45.      * Renderiza um template e retorna o HTML como string
  46.      *
  47.      * @param string $name    Nome do template (sem extensão)
  48.      * @param array  $data    Variáveis para substituir no template
  49.      * @param bool   $minify  Minifica o resultado
  50.      *
  51.      * @throws RuntimeException         se o arquivo não existir
  52.      * @throws InvalidArgumentException se $data não for array
  53.      *
  54.      * @example
  55.      *   $tpl = new Template();
  56.      *   echo $tpl->render('home', ['titulo' => 'Olá Mundo']);
  57.      */
  58.     public function render(string $name, array $data = [], bool $minify = false): string {
  59.         $raw = $this->load($name);
  60.  
  61.         $output = $this->replace($raw, $data);
  62.  
  63.         if ($minify) {
  64.             $output = $this->minify($output);
  65.         }
  66.  
  67.         return $output;
  68.     }
  69.  
  70.     /**
  71.      * Renderiza e envia direto para o output com o Content-Type correto
  72.      *
  73.      * @param string $name
  74.      * @param array  $data
  75.      * @param bool   $minify
  76.      * @param string $contentType  Ex: 'text/html; charset=UTF-8'
  77.      *
  78.      * @example
  79.      *   $tpl->output('home', ['titulo' => 'Olá'], minify: true);
  80.      *   $tpl->output('style', [], contentType: 'text/css');
  81.      */
  82.     public function output(
  83.         string $name,
  84.         array  $data        = [],
  85.         bool   $minify      = false,
  86.         string $contentType = 'text/html; charset=UTF-8'
  87.     ): void {
  88.         if (headers_sent($file, $line)) {
  89.             throw new RuntimeException(
  90.                 "Template: headers já enviados em {$file}:{$line}"
  91.             );
  92.         }
  93.  
  94.         header('Content-Type: ' . $contentType);
  95.         echo $this->render($name, $data, $minify);
  96.     }
  97.  
  98.     // -------------------------------------------------------------------------
  99.     // CACHE
  100.     // -------------------------------------------------------------------------
  101.  
  102.     /**
  103.      * Pré-carrega um ou mais templates na memória
  104.      *
  105.      * @example
  106.      *   $tpl->preload(['header', 'footer', 'home']);
  107.      */
  108.     public function preload(array $names): void {
  109.         foreach ($names as $name) {
  110.             $this->load($name);
  111.         }
  112.     }
  113.  
  114.     /**
  115.      * Limpa o cache em memória
  116.      */
  117.     public function clearCache(?string $name = null): void {
  118.         if ($name === null) {
  119.             $this->cache = [];
  120.         } else {
  121.             unset($this->cache[$name]);
  122.         }
  123.     }
  124.  
  125.     // -------------------------------------------------------------------------
  126.     // PRIVADOS
  127.     // -------------------------------------------------------------------------
  128.  
  129.     /**
  130.      * Carrega o template do disco ou do cache em memória
  131.      *
  132.      * @throws RuntimeException se o arquivo não existir
  133.      */
  134.     private function load(string $name): string {
  135.         if (isset($this->cache[$name])) {
  136.             return $this->cache[$name];
  137.         }
  138.  
  139.         $path = $this->dir . DIRECTORY_SEPARATOR . $name . $this->ext;
  140.  
  141.         if (!file_exists($path)) {
  142.             throw new RuntimeException(
  143.                 "Template: arquivo não encontrado — \"{$name}{$this->ext}\""
  144.             );
  145.         }
  146.  
  147.         $this->cache[$name] = file_get_contents($path);
  148.  
  149.         return $this->cache[$name];
  150.     }
  151.  
  152.     /**
  153.      * Substitui os placeholders {chave} pelos valores de $data
  154.      * Placeholders sem correspondência são mantidos no output
  155.      */
  156.     private function replace(string $template, array $data): string {
  157.         foreach ($data as $key => $value) {
  158.             $template = str_replace('{' . $key . '}', (string) $value, $template);
  159.         }
  160.  
  161.         return $template;
  162.     }
  163.  
  164.     /**
  165.      * Minifica HTML, CSS ou JS de forma segura
  166.      *
  167.      * - Remove comentários HTML  <!-- ... -->
  168.      * - Remove comentários CSS   /* ... */
  169.      * - Colapsa espaços e quebras de linha entre tags HTML
  170.      * - NÃO toca em conteúdo dentro de <pre>, <script> ou <style>
  171.      *   para evitar quebrar código
  172.      */
  173.     private function minify(string $content): string {
  174.         // Remove comentários HTML (não remove condicionais <!--[if ...]>)
  175.         $content = preg_replace('/<!--(?!\[if).*?-->/s', '', $content);
  176.  
  177.         // Remove comentários CSS/JS  /* ... */
  178.         $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
  179.  
  180.         // Colapsa múltiplas quebras de linha e tabs em um único espaço
  181.         $content = preg_replace('/\s{2,}/u', ' ', $content);
  182.  
  183.         // Remove espaços entre tags HTML
  184.         $content = preg_replace('/>\s+</u', '><', $content);
  185.  
  186.         return trim($content);
  187.     }
  188.  
  189. }
  190.  
  191. USO
  192. $tpl = new Template('template', '.tpl');
  193.  
  194. // Retorna string
  195. $html = $tpl->render('home', ['titulo' => 'Olá Mundo']);
  196.  
  197. // Envia direto com header
  198. $tpl->output('home', ['titulo' => 'Olá'], minify: true);
  199.  
  200. // CSS com Content-Type correto
  201. $tpl->output('style', [], contentType: 'text/css');
Advertisement
Add Comment
Please, Sign In to add comment