简单的模板 var 替换,但有一些变化

发布于 2024-09-08 00:59:24 字数 1137 浏览 7 评论 0原文

因此,我正在设置一个包含大量电子邮件和其中的变量替换的系统,因此我正在编写一个类来管理存储在数据库中的模板的一些变量替换。

这是一个简短的例子:

// 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); 

现在,这对于单个 var 替换、基本的东西来说效果很好。但是,有些地方应该有 for 循环,但我不知道如何实现它。

这个想法是有一个像这样的模板:

“您好,%customer_name%,谢谢您 请求有关{产品}的信息”

其中,{products} 将是传递给模板的数组,该数组将循环遍历以获取所请求的产品,格式如下:

我们的产品 %product_name% 有费用 %product_price%。了解更多信息,请访问 %product_url%。

因此,它的渲染版本示例如下:

“你好,鲍勃,谢谢你的请求 相关信息:

我们的产品 WidgetA 的成本为 1 美元。 在示例/A 中了解更多信息

我们的产品 WidgetB 的成本为 2 美元。 了解更多示例/B

我们的产品 WidgetC 的成本为 3 美元。 在 example/C 中了解更多信息。

实现这一目标的最佳方法是什么?

So I'm setting up a system that has a lot of emails, and variable replacement within it, so I'm writing a class to manage some variable replacement for templates stored in the database.

Here's a brief example:

// 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); 

Now, that works well and good for single var replacements, basic stuff. However, there are some places where there should be a for loop, and I'm lost how to implement it.

The idea is there'd be a template like this:

"hello, %customer_name%, thank you for
requesting information on {products}"

Where, {products} would be an array passed to the template, which the is looped over for products requested, with a format like:

Our product %product_name% has a cost
of %product_price%. Learn more at
%product_url%.

So an example rendered version of this would be:

"hello, bob, thank you for requesting
information on:

Our product WidgetA has a cost of $1.
Learn more at example/A

Our product WidgetB has a cost of $2.
Learn more at example/B

Our product WidgetC has a cost of $3.
Learn more at example/C.

What's the best way to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最近可好 2024-09-15 00:59:24

好吧,我真的不明白使用 repalcements/regex 的模板引擎有什么意义

PHP 已经是一个模板引擎了,当你写 它就像做 ><{$var}>{$var}

这样想,PHP 已经翻译了 hello'?> 被其引擎转换为 hello,那么为什么让它把所有事情都做两次呢。

我实现模板引擎的方式如下

首先创建一个模板类

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 一样设置数据,如果您的不确定。当您运行输出命令时,它将数据和 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 混合在一起,但这没关系,因为在 ehre 中你应该只使用基本的东西,例如 Foreach、For 等和变量。


注意:在TemplateLoader类中,您可以添加一个函数,例如..

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

这将允许您在模板中增加操作,例如粗体,斜体,atuoloop,css_secure,stripslashs..

您仍然拥有所有常规工具,例如stripslashes / 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,那么这不是问题,在模板中传入 tpl 文件名只需搜索 db 而不是文件系统

Well, I really dont see the point in a template engine that uses repalcements/regex

PHP Is already a template engine, when you write <?php echo $var?> its just like doing <{$var}> or {$var}

Think of it this way, PHP Already translates <?php echo '<b>hello</b>'?> into <b>hello</b> by its engine, so why make it do everything 2 times over.

The way i would implement a template engine is like so

Firstly create a template class

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;
   }
}

This is what you use in your login such as index.php, you will set data just like an stdClass just google it if your unsure. and when you run the output command it sends the data and tpl to the next class below.


And then create a standalone class to compile the tpl file within.

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>';
   }
}

The reason we keep this seperate is so it has its own space to run in, you just load your tpl file as an include in your constructor so it only can be loaded once, then when the file is included it has access to all the data and methods within 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
?>

Now here we dont really want to mix html with this page because by seperating the php and the view / templates you making sure all your php has completed because when you send html or use html it stops certain aspects of your script from running.


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

Now here we can see that were mixing html with php but this is ok because in ehre you should only use basic stuff such as Foreach,For etc. and Variables.


NOTE: IN the TemplateLoader Class you can add a function like..

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

This will allow you to increase your actions in your templates so bold,italic,atuoloop,css_secure,stripslashs..

You still have all the normal tools such as stripslashes/htmlentites etc.

Heres a small example of the bold.

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

You can add lots of tools into the TempalteLoader class such as inc() to load other tpl files, you can develop a helper system so you can go $this->helpers->jquery->googleSource

If you have any more questions feel free to ask me.

----------

An example of storing in your database.

<?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.
    }
}
?>

If you wish to store your tpl files including PHP then that's not a problem, within Template where you passing in the tpl file name just search db instead of the filesystem

等数载,海棠开 2024-09-15 00:59:24
$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}
$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);

The idea is to find string between {products} and {products}, pass it to some function, do whatever you need to do with it, iterating over $products array.
Whatever the function returns replaces whole "{products}[anything here]{/products}".

The input string would look like that:

Requested products: {products}%product_name%{/products}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文