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>}
语法,表达式用于输出数据。数据默认总是转义,除非在关闭 }
之前使用 =
修饰符。使用 @
符号来访问 主题 的属性(尽管你也可以使用 this
)。
#{@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
CSS 资产可以通过 p:document: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
JavaScript 资产可以通过 p:document:js
元素收集并渲染成 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文件获取详细信息。