torbenkoehn / php-xtpl
PHP 模板引擎
Requires
- php: >=5.3.0
This package is auto-updated.
Last update: 2024-09-10 08:20:57 UTC
README
XTPL 是一个 PHP 的模板系统,它不使用任何花哨的新语法,而是使用普通的旧 HTML,或者说 XML。
它是如何工作的?
XTPL 解析器 解析 XTPL 文件并处理找到的特定节点。节点插件是动态加载的,这意味着像将整个扩展映射到你的 HTML 代码上以处理新和现有 HTML 元素等功能是很容易实现的。
你得到的是 PHTML,你可以将其包含在 PHP 中。PHTML 只是 PHP 与 HTML 的结合,它渲染一个动态的服务器端处理的 HTML 页面。
如果你不想自己处理 PHTML 的事情,XTPL 包含了一个渲染器,如果你喜欢,它还会为你缓存。
如何安装?
你可以通过下载 GitHub 上的 ZIP 文件 或使用 Composer 来安装。
要使用 Composer 安装,你需要在你的 composer.json
中添加以下信息
{ "minimum-stability": "dev", "require": { "php": ">=5.3.0", "torbenkoehn/php-xtpl": "*" } }
之后,只需运行
$ composer install
即可安装 XTPL 库并使其可供使用。
如何使用?
你可以让 XTPL 渲染器处理所有工作,或者你可以动手使用原始 API 来处理。
最简单的方法
$xtpl = new Xtpl\Renderer; $xtpl->displayFile( 'your/path/to/the/xtpl/file', array( 'title' => 'My Page Title', 'posts' => array( 0 => array( 'title' => 'Some post title', 'content' => 'bla bla bla bla bla' ) ) ) );
无论你是否使用 .xtpl
扩展,都没有关系。
使用类似显示的方式将执行 eval()
代码,众所周知,eval 是邪恶的。你最好将缓存目录作为第一个参数传递给渲染器
$xtpl = new Xtpl\Renderer( __DIR__.'/cache' );
当然,这个目录需要可写,但这将大大提高系统的性能。
使用这种方式,渲染器将自动处理所有缓存,你不需要做任何事情。
如果你想深入了解,你还可以以更原始的方式使用该系统,如下所示
$xtpl = $xtpl->renderFileToFile( 'your/xtpl', './phtml/your/xtpl.phtml' ); extract( $yourTemplateArgs ); include './phtml/your/xtpl.phtml';
注意: 对于其他任何内容,请查看上面的代码和下面的文档。
基本功能
块
你可以定义一个块,并让其他块在其中添加或替换内容。这是递归的,这意味着你可以在布局模板中定义块,从它扩展并仅定义块内容。你还可以定义块,然后包含指定块内容的模板。
my-page.xtpl
<?xml version="1.0" encoding="utf-8" ?> <xtpl> <html version="5"> <head> <title>XTPL is awesome!</title> <block name="scripts"> <script src="jquery.js" /> </block> <block name="styles"> <link rel="stylesheet" href="style.css" /> </block> </head> <body> <block name="content"> I'm some placeholder content, I won't stay here. </block> </body> </html> <block name="scripts" mode="append"> <script src="bootstrap.js" /> </block> <block name="styles" mode="prepend"> <link rel="stylesheet" href="bootstrap.css" /> </block> <block name="content"> <h1>My current content</h1> <p> This might be some static or dynamic content, whatever you prefer. </p> <p> It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it. </p> </block> </xtpl>
注意: 实际上,你不再需要关闭脚本元素了。
生成的 HTML 将是这样的
<!doctype html> <html> <head> <title>XTPL is awesome!</title> <script src="jquery.js"></script> <script src="bootstrap.js"></script> <link rel="stylesheet" href="bootstrap.css"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>My current content</h1> <p> This might be some static or dynamic content, whatever you prefer. </p> <p> It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it. </p> </body> </html>
请注意,脚本块被附加,样式块被预先插入,内容块替换了先前的内容。
目标块总是解析器找到的第一个具有该名称的块,其他块将添加到它(或不会添加)
那些玩过 Jade 的人应该知道这种模板机制。
扩展
模板可以扩展其他模板。如果你来自 Jade,你应该已经知道了工作方式。这并没有做什么比将你的当前模板 DOM 放入扩展的模板 DOM 中更多,但它允许递归块使用,全局布局和类似的东西。
想象一下,你有一个非常好的主布局
layout.xtpl
<?xml version="1.0" encoding="utf-8" ?> <xtpl> <html version="5"> <head> <title>XTPL is awesome!</title> <block name="scripts"> <script src="jquery.js" /> </block> <block name="styles"> <link rel="stylesheet" href="style.css" /> </block> </head> <body> <block name="content"> I'm some placeholder content, I won't stay here. </block> </body> </html> </xtpl>
并且你渲染了一个扩展它的模板
my-page.xtpl
<?xml version="1.0" encoding="utf-8" ?> <xtpl extends="layout"> <block name="scripts" mode="append"> <script src="bootstrap.js" /> </block> <block name="styles" mode="prepend"> <link rel="stylesheet" href="bootstrap.css" /> </block> <block name="content"> <h1>My current content</h1> <p> This might be some static or dynamic content, whatever you prefer. </p> <p> It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it. </p> </block> </xtpl>
生成的 HTML 将是这样的
<!doctype html> <html> <head> <title>XTPL is awesome!</title> <script src="jquery.js"></script> <script src="bootstrap.js"></script> <link rel="stylesheet" href="bootstrap.css"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>My current content</h1> <p> This might be some static or dynamic content, whatever you prefer. </p> <p> It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it. </p> </body> </html>
实际上,在扩展层级、块的数量等方面没有任何编程限制。你可以根据需要深入扩展布局,即使在包含的 XTPL 中也是如此。
尽量避免递归
注意: 实际上,递归现在可能会把一切搞砸。
包含
包含子模板。在子模板中,你可以访问模板变量以及包含元素的属性。
my-page.xtpl
<?xml version="1.0" encoding="utf-8"?> <xtpl> <body> <block name="page-header" /> <header> <include file="navigation" orientation="vertical" /> </header> </body> </xtpl>
navigaton.xtpl
<?xml version="1.0" encoding="utf-8"?> <xtpl> <nav class="nav nav-[[orientation]]"> <ul> <li><a href="#home">Home</a></li> <li><a href="#about-me">About me</a></li> <li><a href="#blog">Blog</a></li> <li><a href="#portfolio">Portfolio</a></li> </ul> </nav> <block name="page-header"> My Page Header </block> </xtpl>
要在包含的模板(或任何扩展模板)中使用 orientation
属性,你可以在任何属性或文本节点中使用 [[orientation]]
,看看 <nav>
元素的 class=""
属性。这也适用于扩展了包含模板的模板。orientation
只是一个例子,你可以使用任何你喜欢的属性名或值(你甚至可以加载 file
属性的值)
[[attributeName]]
的插值在属性值和纯文本节点上工作。
变量
还有什么,这是最重要的部分之一。在模板中使用变量有两种方式,有一个 <var>
元素,并且你可以使用插值。
<var>
元素
<var name="my.variable.name" />
是相同的
<?php echo $my->variable->name; ?>
你还可以设置
<var name="my.variable.name" value="New Value!" />
如果变量未设置,则可以使用默认值(这会自动进行 !empty()
检查)
<var name="title" default="My Website Title!" />
但这使用了官方的 <var>
标签,不是吗?
是的,但它不会以任何方式影响它。VarElement 仅在存在至少一个 name
属性时才会响应(在正常的 <var>
元素上设置一个没有任何理由)。其余的仍然是纯 HTML。
插值
变量插值在属性值和文本节点上工作。类似于 <{{var.name}}>
的东西是不可能的,可能永远不会。
<nav class="nav nav-{{orientation}}"> Hey, this is some text and I don't want to use a tag now so I just {{output}} my variable named "output" here. </nav>
注意: 如果你认为在 <php>
节点中使用插值是有意义的,你可以这样做,但说实话,这没有意义。你无论如何都可以通过简单的 $varName
访问变量。尽管如此,在某些情况下可能是有意义的,所以它也工作。
至于属性,如果变量是属性值中唯一的东西,并且变量为 null 或 false,则不会渲染该属性。这对于可选类很有用
<a href="my-link.html" class="{{link.active}}">My link!</a>
如果 $link->active
是 null
或 false
,这将渲染
<a href="my-link.html">My link!</a>
实际上,这是一个谎言,现在它不会这样做,但很快就会。
你还可以在表达式的调用方式中使用默认值和回调/过滤器。
<p> HEY, THE NEXT TEXT SHOULD ALSO BE {{someText(I dont have a Text):strtoupper:SomeClass.doSomeStaticStuff}} </p>
循环
现在有 for 和 foreach 循环。两者都使用 <for>
元素。
一个简单的 foreach 循环工作如下
<for each="my.posts" as="post"> <article> <header> <h1>{{post.title}}</h1> </header> <p> {{item.content}} </p> </article> </for>
你也可以通过
<for each="my.posts" as="post" key="currentIndex">
for 循环目前只是一个计数器,你可以多次执行某项操作并指定一个起点。现在这非常没有用,因为你不能为 times
属性使用插值,但将来这肯定会被改变。
for 循环工作如下
<for times="5" as="i"> ({{i}}): Hey, this should happen 5 times! </for>
条件
是的,它们现在有了!XTPL 支持 <if>
、<else>
和 <elseif>
块。后两个始终需要位于它们引用的 if
元素内部。
通过属性进行的可能检查有 empty
、not-empty
、set
、not-set
、cond
和 not-cond
cond
和 not-cond
只翻译成纯 PHP,它就像在 PHP 中定义 if 语句中的 (...)
之间的内容。
<if not-empty="myVar"> Heeey, we made sure that {{myVar}} is not empty! </if>
<if cond="!empty( $myVar ) and $myVar > 0"> This gets printed if the condition is true </if>
<if not-set="myVar"> myVar is not set <else> myVar is set! </else> </if>
else/else-if 标签在节点中的位置无关紧要,它们总是会自动在末尾渲染。如果你想在大型 if 块的顶部放置 else 块以提高可读性,这很有用。
<if not-set="myVar"> myVar is not set <else> myVar is set! </else> and here is some more content<br> but this will only be rendered, if the if-block is true! </if>
<if not-set="myVar"> myVar is not set <elseif set="myVar"> myVar is set </elseif> <else> This won't ever be printed. </else> </if>
尝试使用它,感受它,它实际上真的可以工作!
行内PHP
您可以使用PHP-HTML标签在模板中使用纯PHP。通过XML限制,您必须将复杂代码放入<![CDATA[ ... ]]>
标签中。
<php>echo $someVariable;</php> <php>while( $i < 10 ):</php> <span>{{i}}</span> <php>$++;</php> <php>endwhile;</php> <php><![CDATA[ //Here you can use any kind of complex PHP code class SomeClass {} $instance = new SomeClass; $instance->something = 'SomeValue'; var_dump( $instance ); ]]></php>
处理指令
您已经看到可以使用标签进行行内PHP。实际上,您还可以在任何XTPL文件中使用<?php ... ?>
语法。这些被处理为处理指令,并直接转换为元素。
以下是一些可用的处理指令
<?php [您的PHP代码] ?>
转换为<php>
元素,在PHTML文件中渲染实际的PHP代码块。
<?css [您的CSS] ?>
转换为有效的<style>
元素
<?js [您的JavaScript] ?>
转换为有效的<script>
元素
扩展
XTPL可以通过非常简单的方式扩展。
解析器从特定的命名空间获取节点。您可以为解析器添加任何喜欢的命名空间,以提供新的或现有的、重工作的元素。
假设您在XTPL文件中使用了<my-custom-tag>
标签。
解析器会查找其扩展命名空间中的My\Custom\TagElement
类,如果找到,则处理它并将其渲染为有效的XTPL节点。
由于新添加的命名空间始终首先被读取,因此可以很容易地通过这种方式删除整个元素命名空间。下一章中提到的Bootstrap扩展将给出一个很好的例子。
默认命名空间如下
Xtpl\Nodes
Xtpl\Extensions
要包含一个新命名空间,您可以在Xtpl\Renderer
上调用$renderer->addExtension( 'Your\\Extension\\Namespace' );
或$parser->addElementNamespace( 'Your\\Extension\\Namespace' );
在Xtpl\Parser
上。
要启用XTPL扩展,您可以在Xtpl\Renderer
上调用$renderer->addXtplExtension( 'ExtensionName' )
或$parser->addElementNamespace( 'Xtpl\\Extensions\\ExtensionName' );
在Xtpl\Parser
上。
通常您应该与Xtpl\Renderer
一起工作,了解一下。
默认扩展
虽然您当然可以轻松地自己开发扩展,但您不必这样做。XTPL实际上带来了一整套新的HTML元素。
您可以通过它们的完整命名空间激活它们,或者包含单个命名空间将它们映射到现有的HTML上。
单个扩展(Xtpl\Extensions
)
单个扩展是简单的单个元素,仅提供一些实用功能。
电子邮件
标签<email>someone@example.com</email>
将被转换为<a href="mailto:someone@example.com">someone@example.com</a>
HTML
<html>
标签有一个新属性叫做version
。目前它只支持值5
,这会使它自动在<html>
标签前添加<!doctype html>
。
头部
<head>
扩展实际上只是默认添加UTF-8字符集,如果您没有手动添加。
换行
<br>
标签提供了一个新的属性repeat
,它确实如您所想的那样工作。<br repeat="5" />
将渲染为<br><br><br><br><br>
这在布局中比人们想象的更有用。
Bootstrap扩展(Xtpl\Extensions\Bootstrap
)
Bootstrap扩展是一套新的HTML元素,它们提供了Twitter的Bootstrap框架的全部功能,具有您见过的最简单的标记。
注意: 您不必自己加载bootstrap!XTPL实际上负责这件事,并自动处理bootstrap的脚本和CSS需求。这意味着,一旦您的代码中有Bootstrap元素,您也就有了jQuery。看看生成的DOM吧!
使用bootstrap扩展有两种方法。
直接调用
您可以通过使用它们的命名空间直接调用Bootstrap扩展。记住,Xtpl\Extensions
命名空间始终被加载。使用<bootstrap-button theme="primary">我的闪亮按钮!</bootstrap-button>
,您将获得一个完全工作的Bootstrap-Button,它会自动处理您对它的所有操作。
扩展映射
如果您无论如何都在整个项目中使用Bootstrap,您也可以将整个扩展命名空间映射到您的XTPL文件上。您可以通过启用Bootstrap扩展来实现这一点。只需在您的Xtpl\Renderer
上调用$renderer->addXtplExtension( 'Bootstrap' );
即可。
Bootstrap扩展将78个新元素引入您的XTPL模板。要了解它们的功能,您最好查看以下XTPL模板:
[Bootstrap扩展示例模板](https://github.com/TorbenKoehn/php-xtpl/tree/master/templates/bootstrap-extension)
开发您自己的扩展
目前实际上没有关于扩展元素如何工作的文档。您只需查看现有的Bootstrap-Extension,以全面了解它们是如何制作的。
计划中的功能和修复
- Less和CoffeeScript集成
- Markdown集成
- 更多动态处理指令
- 在节点中改进DOM管理
- 改进固定值属性的插值(例如,
<boostrap-button theme="{{theme}}" />
目前无法正常工作) - Twitter Bootstrap折叠(手风琴)、轮播和固定
- 更多文档类型
- 更智能的编码检测和自动生成
- 更智能和巧妙的单扩展元素
为什么叫XTPL?
老实说,因为我还没有找到任何花哨、合适的名字。也许它将永远被称为XTPL,也许我会在某个时候改变它,我不知道。
XTPL来自XML和Template (TPL),这使得它成为XTPL。很酷,我知道。
我欢迎名字建议。
我有反馈,我很感兴趣,我想贡献力量,我给这个项目起了个新名字?
请发送电子邮件到torben@devmonks.net并告知我。
我期待与感兴趣的人交谈 :)