Простая замена шаблона var, но с изюминкой - PullRequest
1 голос
/ 01 июля 2010

Итак, я настраиваю систему с большим количеством электронных писем и заменой переменных внутри нее, поэтому я пишу класс для управления заменой переменных для шаблонов, хранящихся в базе данных.

Вот краткий пример:

// template is stored in db, so that's how this would get loaded in 
$template = "Hello, %customer_name%, thank you for contacting %website_name%"; 
// The array of replacements is built manually and passed to the class 
// with actual values being called from db 
$replacements = array('%customer_name%'=>'Bob', '%website_name%'=>'Acme'); 
$rendered = str_replace(array_keys($replacements), $replacements, $template); 

Теперь, это хорошо работает для замены одного вар, основной материал. Однако в некоторых местах должен быть цикл for, и я забыл, как его реализовать.

Идея в том, что будет такой шаблон:

"привет,% customer_name%, спасибо за запрос информации о {продукты} "

Где {products} - это массив, переданный шаблону, который зацикливается для запрашиваемых продуктов в следующем формате:

Наш продукт% product_name% имеет стоимость % product_price%. Узнайте больше на % Product_url%.

Таким образом, приведенная в качестве примера версия этого будет:

"Привет, Боб, спасибо за запрос информация о:

Наш продукт WidgetA стоит 1 доллар. Узнайте больше на примере / A

Наш продукт WidgetB стоит $ 2. Узнайте больше на примере / B

Наш продукт WidgetC стоит 3 доллара. Узнайте больше на примере / C.

Какой лучший способ сделать это?

Ответы [ 2 ]

4 голосов
/ 01 июля 2010

Ну, я действительно не вижу смысла в шаблонизаторе, который использует repalcements / regex

PHP - это уже шаблонизатор, когда вы пишете <?php echo $var?>, это все равно что делать <{$var}> или {$var}

Подумайте об этом так, PHP уже переводит <?php echo '<b>hello</b>'?> в <b>hello</b> с помощью своего движка, поэтому зачем заставлять его делать все 2 раза.

Способ, которым я бы реализовал шаблонизаторЭто так

Сначала создайте шаблон класса

class Template
{
   var $vars = array();

   function __set($key,$val)
   {
      $this->vars[$key] = $val;
   }

   function __get($key)
   {
     return isset($this->vars[$key]) ? $this->vars[$key] : false;
   }

   function output($tpl = false)
   {
      if($tpl === false)
      {
         die('No template file selected in Template::output(...)');
      }

      if(!file_exists(($dir = 'templates/' . $tpl . '.php')))
      {
         die(sprintf('Tpl file does not exists (%s)',$dir));
      }

      new TemplateLoader($dir,$this->vars);
      return true;
   }
}

Это то, что вы используете при входе в систему, например index.php, вы будете устанавливать данные так же, как stdClass просто Google, если вы не уверены.и когда вы запускаете выходную команду, она отправляет данные и tpl следующему классу ниже.


, а затем создает автономный класс для компиляции файла tpl в пределах.

class TemplateLoader
{
    private $vars = array();
    private $_vars = array(); //hold vars set within the tpl file
    function __construct($file,$variables)
    {
        $this->vars = $variables;
        //Start the capture;
        ob_start();
           include $file;
           $contents = ob_get_contents();
        ob_end_clean(); //Clean it

       //Return here if you wish
       echo $contents;
    }

    function __get($key)
    {
        return isset($this->vars[$key]) ? $this->vars[$key] : (isset($this->_vars[$key]) ? $this->_vars[$key] : false) : false;
    }

    function __set($key,$val)
    {
       $this->_vars[$key] = $val;
       return true;
    }

   function bold($key)
   {
      return '<strong>' . $this->$key . '</string>';
   }
}

Причина, по которой мы держим это отдельно, состоит в том, что у него есть свое собственное пространство для запуска, вы просто загружаете свой файл tpl как включение в ваш конструктор, чтобы его можно было загрузить только один раз, затем, когда файл включен, он имеет доступ ко всем данным.и методы в TemplateLoader.


Index.php

<?php
   require_once 'includes/Template.php';
   require_once 'includes/TemplateLoader.php';


   $Template = new Template();

   $Template->foo = 'somestring';
   $Template->bar = array('some' => 'array');

   $Template->zed = new stdClass(); // Showing Objects

   $Template->output('index'); // loads templates/index.php
?>

Теперь мы не хотим смешивать html с этой страницей, потому что разделяя php и представление / шаблоны, которые вы делаетеуверен, что весь ваш php завершен, потому что когда вы отправляете html или используете html, он останавливает выполнение некоторых аспектов вашего скрипта.


templates / index.php

header

    <h1><?php $this->foo;?></h1>
    <ul>
        <?php foreach($this->bar as $this->_foo):?>
            <li><?php echo $this->_foo; ?></li>
        <?php endforeach; ?>
    </ul>
     <p>Testing Objects</p>
     <?php $this->sidebar = $this->foo->show_sidebar ? $this->foo->show_sidebar : false;?>
     <?php if($this->sidebar):?>
        Showing my sidebar.
     <?php endif;?>
footer

Теперь здесь мыможно видеть, что html смешивался с php, но это нормально, потому что в прошлом вы должны использовать только базовые вещи, такие как Foreach, For и т. д. и переменные.


ПРИМЕЧАНИЕ: В TemplateLoader Class, вы можете добавить такую ​​функцию, как ..

function bold($key)
{
   return '<strong>' . $this->$key . '</string>';
}

Это позволит вам увеличить ваши действия в ваших шаблонах таким жирным шрифтом, курсивом, atuoloop, css_secure, stripslashs ..

Вы по-прежнемуесть все обычные инструменты, такие как полоски / htmlentites и т. д.

Вот небольшой пример жирного шрифта.

$this->bold('foo'); //Returns <strong>somestring</string>

В класс TempalteLoader можно добавить множество инструментов, таких какinc () для загрузки других файлов tpl, вы можете разработать вспомогательную систему, чтобы вы могли идти $this->helpers->jquery->googleSource

Если у вас есть еще вопросы, не стесняйтесь спрашивать меня.

----------

Пример хранения в вашей базе данных.

<?php
if(false != ($data = mysql_query('SELECT * FROM tpl_catch where item_name = \'index\' AND item_save_time > '.time() - 3600 .' LIMIT 1 ORDER BY item_save_time DESC')))
{
    if(myslq_num_rows($data) > 0)
    {
       $row = mysql_fetch_assc($data);
       die($row[0]['item_content']);
    }else
    {
       //Compile it with the sample code in first section (index.php)
       //Followed by inserting it into the database
       then print out the content.
    }
}
?>

Если вы хотите хранить свои файлы tpl , включая PHP тогда это не проблема, в Template, где вы передаете имя файла tpl, просто ищите db вместо файловой системы

0 голосов
/ 01 июля 2010
$products = array('...');
function parse_products($matches)
{
    global $products;
    $str = '';
    foreach($products as $product) {
       $str .= str_replace('%product_name%', $product, $matches[1]); // $matches[1] is whatever is between {products} and {/products}
    }
    return $str;
}

$str = preg_replace_callback('#\{products}(.*)\{/products}#s', 'parse_products', $str);

Идея состоит в том, чтобы найти строку между {products} и {products}, передать ее какой-либо функции, сделать с ней все, что вам нужно, итерируя по массиву $ products.Что бы функция не возвращала, она заменяет целые "{products} [что-нибудь здесь] {/ products}".

Входная строка будет выглядеть так:

Requested products: {products}%product_name%{/products}
...