rgamba/tonic

超快且强大的PHP模板引擎

3.0 2015-03-27 05:09 UTC

This package is not auto-updated.

Last update: 2024-09-28 17:54:29 UTC


README

Build Status

超快且强大的模板引擎。纯PHP,无依赖。

用法

使用Tonic非常直接。

use Tonic\Tonic;
$tpl = new Tonic("demo.html");
$tpl->user_role = "member";
echo $tpl->render();

它也非常灵活。上面的代码也可以写成这样

$tpl = new Tonic();
echo $tpl->load("demo.html")->assign("user_role","member")->render();

显示语法

使用Tonic

<body>
<h1>Welcome {$user.name.capitalize().truncate(50)}</h1>
User role: {$role.lower().if("admin","administrator").capitalize()}
</body>

与纯PHP编写相比

<body>
<h1>Welcome <?php echo (strlen($user["name"]) > 50 ? substr(ucwords($user["name"]),0,50)."..." : ucwords($user["name"])) ?></h1>
User role: <?php if(strtolower($role) == "admin") { echo "Administrator" } else { echo ucwords($role) } ?>
</body>

安装

使用composer安装

$ composer require rgamba/tonic

缓存

所有tonic模板都会编译回原生PHP代码。强烈建议您使用缓存功能,这样相同的模板就不需要反复编译,从而减少服务器端的CPU使用。

$tpl = new Tonic();
$tpl->cache_dir = "./cache/"; // Be sure this directory exists and has writing permissions
$tpl->enable_content_cache = true; // Importante to set this to true!

修饰符

修饰符是各种方式修改输出变量的函数。所有修饰符都必须在变量之前,并且可以与其他修饰符链接。例如

{$variable.modifier1().modifier2().modifier3()}

我们也可以以相同的方式在关联数组中使用修饰符

{$my_array.item.sub_item.modifier1().modifier2().modifier3()}

处理日期

在Tonic模板中处理和格式化日期非常容易。

Tonic::$local_tz = 'America/New_york'; // Optionaly set the user's local tz
$tpl = new Tonic();
$tpl->my_date = date_create();

并且模板

<p>Today is {$my_date.date("Y-m-d h:i a")}</p>

处理时区

<p>The local date is {$my_date.toLocal().date("Y-m-d h:i a")}</p>

这将把 $my_date 渲染为 Tonic::$local_tz 中配置的时区

自定义时区

<p>The local date is {$my_date.toTz("America/Mexico_city").date("Y-m-d h:i a")}</p>

修饰符列表

创建自定义修饰符

如果您需要自定义修饰符,可以扩展列表并创建自己的。

// This function will only prepend and append some text to the variable
Tonic::extendModifier("myFunction",function($input, $prepend, $append = ""){
    // $input will hold the current variable value, it's mandatory that your lambda
    // function has an input receiver, all other arguments are optional
    // We can perform input validations
    if(empty($prepend)) {
        throw new \Exception("prepend is required");
    }
    return $prepend . $input . $append;
});

然后您可以使用这个修饰符

<p>{$name.myFunction("hello "," goodbye")}</p>

匿名修饰符

有时您只需要在模板内部直接调用函数,这些函数的返回值是不断变化的,因此不能与静态变量链接。此外,它的值不依赖于任何变量。在这种情况下,您可以使用匿名修饰符。要做到这一点,您需要创建一个自定义修饰符,如果需要使用其他参数,请忽略 $input 参数。

Tonic::extendModifier("imagesDir", function($input){
    // Note that $input will always be empty when called this modifier anonymously
    return "/var/www/" . $_SESSION["theme"] . "/images";
});

然后您可以直接从模板中调用它

<img src="{$.imagesDir()}/pic.jpg" />

上下文感知

Tonic阻止您在应用程序中逃避可能导致潜在攻击的变量。所有即将显示给用户的变量都应该被仔细转义,并且应该根据其上下文进行转义。例如,链接的href属性中的变量应该以不同的方式转义,而javascript标签或 <h1> 标签中的某些变量。好消息是,Tonic为您做了所有这些工作。

$tonic->assign("array",array("Name" => "Ricardo", "LastName", "Gamba"));
$tonic->assign("ilegal_js","javascript: alert('Hello');");

并且HTML

<a href="{$ilegal_js}">Click me</a>
<!-- Will render: <a href="javascript%3A+alert%28%27Hello%27%29%3B">Click me</a> -->
<p>The ilegal js is: {$ilegal_js}</p>
<!-- Will render: <p> The ilegal js is: javascript: alert(&#039;Hello&#039;);</p> -->
<a href="?{$array}">Valid link generated</a>
<!-- Will render: <a href="?Name=Ricardo&LastName=Gamba">Valid link generated</a> -->
<p> We can also ignore the context awareness: {$ilegal_js.ignoreContext()}</p>

包含模板

您可以在另一个模板中包含一个模板

{include footer.html}

我们还可以获取外部页面并将其加载到当前模板中

{include http://mypage.com/static.html}

模板包含支持嵌套调用,但请注意,在模板“A”中包含模板“A”可能导致无限循环。

控制结构

如果 / 否则

制作条件非常简单

{if $user.role eq "admin"}
<h1>Hello admin</h1>
{elseif $user.role.upper() eq "MEMBER" or $user.role.upper() eq "CLIENT"}
<h1>Hello member</h1>
{else}
<h1>Hello guest</h1>
{endif}

您可以使用常规逻辑运算符(==, !=, >, <, >=, <=, ||, &&)或使用以下

循环

<ul>
{loop $user in $users}
<li>{$user.name.capitalize()}</h1>
{endloop}
</ul>

或者如果需要数组键

<ul>
{loop $i,$user in $users}
<li>{$i} - {$user.name.capitalize()}</h1>
{endloop}
</ul>

处理宏

if结构和循环构造可以以更HTML友好的方式编写,以便您的代码更易于阅读。以下是一个示例

<ul tn-if="$users">
    <li tn-loop="$user in $users">Hello {$user}</li>
</ul>

这完全等同于

{if $users}
<ul>
    {loop $user in $users}
    <li>Hello {$user}</li>
    {endloop}
</ul>
{endif}

模板继承

Tonic支持单模板继承。其背后的理念是保持事物的简洁性。多重继承可能导致复杂的视图难以维护。

在Tonic中,模板继承基于。假设我们有以下基本模板

base.html

<html>
<head>
<title>Tonic</title>
</head>
<body>
<section tn-block="header">
    <h1>Default welcome message!</h1>
</section>
<section>
    <div tn-block="content">
        <p>This is the default content.</p>
    </div>
</section>
<section tn-block="footer">Tonic 2016</section>
</body>

然后你有几个部分模板或视图,并且你希望重用主base.html作为“骨架”。为了做到这一点,我们使用。每个块由标签{block name}{endblock}定义,或者由html属性tn-block="name"定义,该属性将具有属性值的HTML元素实际封装为名为name的块。

inner.html

{ extends base.html }
<section tn-block="header" class="myheader">
    <h1>Welcome to my inner page!</h1>
</section>
<p>This content WON´T be rendered at all!</p>
<div tn-block="content">
    <p>This is the content of my inner view.
</div>

结果,我们将得到以下视图

<html>
<head>
<title>Tonic</title>
</head>
<body>
<section class="myheader">
    <h1>Welcome to my inner page!</h1>
</section>
<section>
    <div>
        <p>This is the content of my inner view.
    </div>
</section>
<section>Tonic 2016</section>
</body>

这里有几个关键字

  • { extend }标签。它唯一且必须的参数应该是相对于Tonic::$root的模板文件(默认为./)。
  • tn-block="header" html属性定义了块,并由HTML元素的闭合匹配标签封装。
  • 所有在子模板(inner.html)中找到的块将有效地替换父模板(base.html)上匹配的块。如果子模板中有一个块在父模板中没有定义,那么该块将完全不被渲染
  • 块名称必须是字母数字的,并且不得包含$或任何特殊字符或空格。
  • 父模板(base.html)继承子模板(inner.html)的上下文(作用域、变量)。
  • 你只能扩展1个模板。

注意也可以使用{block header}{endblock}的表示法来定义块。我们更倾向于使用HTML属性,因为它更干净。例如

{block myBlock}<div><h1>Welcome</h1></div>{endblock}

与以下内容完全相同

<div tn-block="myBlock"><h1>Welcome</h1></div>

变更日志

  • 2016-11-10 - 3.1.0 - 添加了对模板继承的支持
  • 2015-03-25 - 3.0.0 - 添加了上下文感知和宏语法,用于条件语句和循环
  • 2015-03-23 - 2.2.0 - 添加了命名空间支持,并添加了修饰符异常
  • 2015-03-20 - 2.1.0 - 添加了扩展修饰符的选项
  • 2015-03-19 - 2.0.0 - 重要更新。大多数结构的语法略有变化,与旧版本不兼容。