icybee / patron
一个HTML模板引擎
Requires
- php: ^5.5|^7.0
- icanboogie/common: ^1.2
- icanboogie/render: ^0.5
- icybee/bluetihi: ^0.0.3
Suggests
- brickrouge/brickrouge: Required to use p:pager, p:document:css, and p:document:js
- icanboogie/i18n: Required to use the translation notation and markup.
README
Patron 是一个适用于 PHP5.4+ 的模板引擎。它促进了应用程序逻辑和内容与其展示的分离。模板是用 HTML 编写的,包括在模板解析时被替换的表达式,以及控制模板逻辑的特殊标记。
典型示例
<p:articles limit="10"> <p:foreach> <article class="#{@css_class}"> <h1>#{@title}</h1> <div class="article-body">#{@=}</div> <p:if test="@comments"> <section class="article-comments"> <h2>Comments</h2> <p:foreach in="@comments"> <article class="#{@css_class}"> <header> <h3>Comment №#{self.position} by #{@author}</h3> </header> <div class="comment-body">#{@=}</div> </article> </p:foreach> </section> </p:if> </article> </p:foreach> <p:pager /> </p:articles>
特性
- 标记集和函数集易于扩展。
- 块有一个 主题,类似于 JavaScript 中的
this
。 - 使用
#{t:String to translate}
符号轻松翻译。
致谢
这个模板引擎的开发是在大约 2007 年,因为那时 textpattern 不支持嵌套标记,我觉得这会是一个很好的练习。其代码的一部分已经沉睡很长时间了,所以如果你看到一些驼峰式命名,尽管几乎到处都使用蛇形命名,但至少你能识别出 旧的 部分 :-)
表达式
使用 #{<expression>}
符号的表达式用于输出数据。除非在关闭 }
之前使用 =
修饰符,否则数据总是被转义。
#{@title} #{@title.shuffle()} <!-- `title` is passed to str_shuffle() --> #{@title=} <!-- `title` is not escaped --> #{pagination=} <!-- another variable that is not escaped -->
标记集合
可以由 Patron 引擎实例使用的标记定义在 MarkupCollection 实例中,该实例用于创建 Engine 实例。可以使用 get_markups()
辅助函数获取共享的标记集合。当它首次创建时,会触发 MarkupCollection\AlterEvent 类的 MarkupCollection::alter
事件。事件钩子可以使用此事件来修改集合,添加和删除标记定义。
以下示例演示了如何使用事件钩子添加一个支持默认为 "world" 的 name
参数的 hello
标记。
<?php use Patron\Engine; use Patron\MarkupCollection; $app->events->attach(function(MarkupCollection\AlterEvent $event, MarkupCollection $collection) { $collection['hello'] = [ function(array $args, Engine $engine, $template) { return "Hello {$args['name']}!"; }, [ 'name' => "world" ] ]; });
以下标记已定义。
p:if
标记
提供简单的 if-then 条件性。
<p:if test = expression select = expression equals = value> <!-- Content: p:with-param*, template --> </p:if>
应定义 test
或 select
和一个运算符(例如 equals
)。测试是静默的,不应生成通知。
<p:if test="@has_title">This article has a title</p:if> <p:if test="@has_title.not()">This article has no title</p:if> <p:if select="@comments_count" equals="10">This article has 10 comments</p:if>
p:choose
标记
从多个可能的替代方案中选择一个。
<!-- Category: instruction --> <p:choose> <!-- Content: (p:when+, p:otherwise?) --> </p:choose> <p:when test = boolean-expression> <!-- Content: template --> </p:when> <p:otherwise> <!-- Content: template --> </p:otherwise>
它由一系列 p:when
元素和一个可选的 p:otherwise
元素组成。每个 p:when
元素都有一个属性,test,指定一个表达式。p:when
和 p:otherwise
元素的内容是模板。当处理 p:choose
元素时,会按顺序测试每个 p:when
元素,通过评估表达式并将结果对象转换为布尔值(就像调用布尔函数一样)。第一个测试为真的 p:when
元素的内容被实例化。如果没有 p:when
为真,则实例化 p:otherwise
元素的内容。如果没有 p:when
元素为真,并且没有 p:otherwise
元素,则不创建任何内容。
p:foreach
标记
将模板应用于提供的数组中的每个条目。
<p:foreach in = expression | this as = qname | this> <!-- Content: p:with-param*, p:empty?, p:wrap?, template --> </p:foreach>
在每次迭代中,以下变量将在 self
中更新
count
:条目数。position
:当前条目的位置。left
:剩余条目数。even
:如果位置是偶数,则为 "even",否则为空字符串。key
:条目的键。
<p:foreach in="articles"> <p:empty>There is no article yet.</p:empty> <p:wrap><ul>#{@=}</ul></p:wrap> <li>#{self.position}/#{self.count} <a href="#{@url}">#{@title}</a></li> </p:foreach>
p:variable
标记
将名称绑定到值。
<!-- Category: top-level-element --> <!-- Category: instruction --> <p:variable name = qname select = expression> <!-- Content: p:with-param*, template? --> </p:variable> <!-- Category: top-level-element --> <p:param name = qname select = expression> <!-- Content: template? --> </p:param>
变量绑定的值(变量的值)可以是表达式可以返回的任何类型的对象。可以使用两个元素来绑定变量:p:variable
和 p:with-param
。区别在于,在 p:with-param
变量中指定的值仅为绑定的默认值;当调用包含 p:with-param
元素的模板时,可以传递参数,这些参数将用作默认值。
p:variable
和 p:with-param
都有一个必需的 name
属性,该属性指定变量的名称。该 name
属性的值是一个限定名。
<p:variable name="count" select="@comments_count" /> <p:variable name="count">There are #{@comments_count} comments</p:variable>
p:with
标记
解析具有约束值的模板。
<p:with select = expression> <!-- Content: p:with-param*, template --> </p:with>
<p:with select="articles.first().comments.last()"> Last comment: <a href="#{@url}">#{@title}</a> </p:with>
p:decorate
标记
使用模板装饰内容。
<p:decorate with = string> <!-- Content: p:with-param*, template --> </p:decorate>
将标记内容渲染以创建要装饰的组件,然后将其作为 component
变量传递给装饰模板。
使用 with
属性指定装饰模板的名称,例如,如果指定 "page",则使用模板 "@page.html" 或 "partials/@page.html",优先使用前者。
使用 with-param
指定的参数,以及标记的属性(除 with
外)在装饰模板中作为变量提供。
<p:decorate with="page"> <p:page:content id="body" /> </p:decorate>
@page.html
模板
<!DOCTYPE html> <head> </head> <body> #{component=} </body>
p:template
标记
添加模板。
<p:template name = qname> <!-- Content: p:with-param*, template --> </p:template>
name
属性定义了模板的名称。标记的内容定义了模板。
p:call-template
标记
调用模板。
<p:call-template name = qname> <!-- Content: p:with-param* --> </p:call-template>
p:translate
标记
翻译并插值字符串。
<p:translate native = string> <!-- Content: p:with-param* --> </p:translate>
使用标记的属性或 with-param
构造提供插值的参数。
示例
<p:translate native="Posted on :date by !name"> <p:with-param name="date"><time datetime="#{@date}" pubdate="pubdate">#{@date.format_date()}</time></p:with-param> <p:with-param name="name" select="@user.name" /> </p:translate>
p:document:css
标记
可以使用 p:document:css
元素收集 CSS 资产并将其渲染到 LINK
元素中。使用 href
属性将资产添加到集合中。使用 weight
属性指定该资产的权重。如果没有指定 weight
属性,则资产的权重默认为 100。如果没有指定 href
属性,则渲染资产。如果指定了模板,则将集合作为 this
传递,否则将集合渲染为 LINK
元素的 HTML 字符串。
注意:此标记需要 brickrouge/brickrouge 包。
<p:document:css href = string weight = int> <!-- Content: p:with-params, template? --> </p:document:css>
示例
<p:document:css href="/public/page.css" /> <p:document:css href="/public/reset.css" weight="-100" /> <p:document:css />
将生成
<link href="/public/reset.css" type="text/css" rel="stylesheet" /> <link href="/public/page.css" type="text/css" rel="stylesheet" />
p:document:js
标记
可以使用 p:document:js
元素收集 JavaScript 资产并将其渲染到 SCRIPT
元素中。使用 href
属性将资产添加到集合中。使用 weight
属性指定该资产的权重。如果没有指定 weight
属性,则资产的权重默认为 100。如果没有指定 href
属性,则渲染资产。如果指定了模板,则将集合作为 this
传递,否则将集合渲染为 SCRIPT
元素的 HTML 字符串。
注意:此标记需要 brickrouge/brickrouge 包。
<p:document:js href = string weight = int> <!-- Content: p:with-params, template? --> </p:document:js>
示例
<p:document:js href="/public/page.js" /> <p:document:js href="/public/reset.js" weight="-100" /> <p:document:js />
将生成
<script src="/public/reset.css" type="text/javascript"></script> <script src="/public/page.css" type="text/javascript"></script>
p:pager
标记
渲染页面元素。
注意:此标记需要 brickrouge/brickrouge 包。
<p:pager count = int page = int limit = int with = string range = expression noarrows = boolean> <!-- Content: p:with-param*, template? --> </p:pager>
函数集合
可以由Patron引擎实例使用的函数定义在FunctionCollection实例中,该实例用于创建Engine实例。可以使用get_functions()
辅助函数来获取共享的标记集合。当它首次创建时,将触发类FunctionCollection\AlterEvent的FunctionCollection::alter
事件。事件钩子可以使用此事件来修改集合,添加和删除函数。
以下示例演示了如何使用事件钩子添加一个hello
函数
<?php use Patron\Engine; use Patron\FunctionCollection; $app->events->attach(function(FunctionCollection\AlterEvent $event, FunctionCollection $collection) { $collection['hello'] = function($name="world") { return "Hello $name!"; }; });
以下函数是默认定义的
if
:如果a是真值,则返回b,否则返回c。or
:如果a是真值,则返回a,否则返回b。not
:返回否定值。mod
:两个值的模。bit
:检查是否定义了位。greater
:检查a是否大于b。smaller
:检查a是否小于b。equals
:检查a是否等于b。different
:检查a是否不同于b。add
:将两个值相加。minus
:从一个值中减去另一个值。plus
:将两个值相加。times
:乘以一个值。by
:除以一个值。split
:将字符串分割为数组。joint
:将数组连接成字符串。index
:返回指定索引的值。first
:返回数组的第一个元素,或前n个元素。to_s
:将值转换为字符串。replace
:替换字符串。markdown
:使用Markdown将字符串转换为HTML。
查找函数
使用find()
方法在集合中查找函数,它还可以检查集合外部定义的函数,例如PHP函数。
<?php echo $functions->find('boot'); // ICanBoogie\boot
执行函数
您可以使用find()
方法查找函数,然后使用返回的值调用该函数,或者您可以直接像调用FunctionCollection的方法一样调用该函数。
<?php use Patron\FunctionCollection; $functions = new FunctionCollection([ 'hello' => function($name = "world") { return "Hello $name!"; } ]); echo $functions->hello("Olivier"); // Hello Olivier!
如果调用的函数未定义,将抛出FunctionNotDefined异常。
事件钩子
ICanBoogie\Core::boot
:此事件用于将事件钩子附加到MarkupCollection::alter
和FunctionCollection::alter
,以便添加在patron.markups
和patron.function
配置中定义的标记和函数。
要求
该包需要PHP 5.4或更高版本。
安装
推荐通过Composer安装此包。
$ composer require icybee/patron
以下包是必需的,您可能需要检查它们
克隆仓库
该包可在GitHub上找到,可以使用以下命令行克隆其仓库
$ git clone https://github.com/Icybee/Patron.git
文档
该包作为[ICanBoogie][]框架的一部分进行了文档说明文档。您可以使用make doc
命令生成包及其依赖项的文档。文档生成在build/docs
目录中。需要ApiGen
。可以使用make clean
命令清理该目录。
测试
测试套件使用make test
命令运行。PHPUnit和Composer需要全局可用才能运行套件。该命令按需安装依赖。执行make test-coverage
命令将运行测试套件并在"build/coverage"目录中创建HTML覆盖率报告。该目录可以用make clean
命令清理。
该软件包由Travis CI持续测试。
许可证
本软件包受新BSD许可证的许可 - 详细信息请参阅LICENSE文件。