pyrocms / lex
轻量级模板解析器。
Requires
- php: >=5.3.0
Replaces
- fuel/lex: *
This package is not auto-updated.
Last update: 2024-09-14 14:11:08 UTC
README
Lex 是一个轻量级模板解析器。
Lex 在 MIT 许可证下发布,版权所有 2011 - 2014 PyroCMS 团队。
变更日志
2.3.2
- 仅在
parser()
方法开始处使用->toArray()
将对象转换为数组。 - 尽管我们希望与 PHP 5.3 说再见,但我们现在将其带了回来。
2.3.1
- 添加了 ArrayableInterface,它将对象自动转换为数组。这允许通过添加
->toArray()
方法来定义对象如何转换为数组。 - 现在会检查循环数据是否为数组或实现了 \IteratorAggregate。这可以防止在 foreach 中出现“无效的参数”错误,同时允许数组和 Collection 对象可迭代。
- 停止支持 PHP 5.3
2.3.0
- 添加了对自闭合回调标签的支持(例如,
{{ foo.bar /}}
而不是{{ foo.bar }}{{ /foo.bar }}
)。 - 回滚了使回调标签不那么贪婪的更改。回调标签现在再次贪婪。如果您想在同一个模板中使用单标签和块标签,必须关闭单标签。
2.2.3
- 修复了导致所有回调都作为单标签处理的问题,即使它们是块。
2.2.2
- 修复了 #7 - 循环数据标签中的条件现在按预期工作。
2.2.1
- 将 injectNoparse 修改为静态。
2.2.0
- 修复了一个仅适用于 PHP 5.4 的测试。
- 将 PHPUnit 添加为 composer 开发要求。
- 添加了一个 Lex\ParsingException 类,当发生解析异常时抛出。
2.1.1
- 修复了回调函数返回的字符串在比较条件中被错误处理的问题,导致条件始终失败。
2.1.0
- 条件中的未定义变量现在评估为 NULL,因此
{{ if foo }}
现在可以正常工作。 - 添加了
exists
关键字。 - 添加了
not
关键字。
2.0.3
- 修复了 composer 自动加载。
- 将类移动到 lib 文件夹。
2.0.2
- 修复了 2.0.1 中引入的 NULL 变量未显示的 bug。
2.0.1
- 修复了具有“假值”(例如,0、"0"、-1 等)的变量未显示的 bug。
2.0.0
- 所有代码现在遵循 PSR-0、1 和 2。
- Lex_Parser 已移动到
Lex
命名空间并重命名为Parser
。 - Lex_Autoloader 已删除。它现在遵循 PSR-0。
- 添加了对
{{ unless }}
和{{ elseunless }}
的支持。
基本用法
使用 Lex
Lex 是一个名为 pyrocms/lex
的 Composer 包。要使用它,只需将其添加到您的 composer.json
文件的 require
部分即可。
{
"require": {
"pyrocms/lex": "2.2.*"
}
}
在将 Lex 添加到您的 composer.json
文件后,只需像平常一样使用该类。
$parser = new Lex\Parser();
使用 Lex
基本文件解析
$parser = new Lex\Parser();
$template = $parser->parse(file_get_contents('template.lex'), $data);
您还可以设置作用域粘合剂(请参阅下面的“作用域粘合剂”)
$parser = new Lex\Parser();
$parser->scopeGlue(':');
$template = $parser->parse(file_get_contents('template.lex'), $data);
要允许无解析提取累积,以便它们不会被后续调用解析器解析,请将 cumulativeNoparse 设置为 true
$parser = new Lex\Parser();
$parser->cumulativeNoparse(true);
$template = $parser->parse(file_get_contents('template.lex'), $data);
// Second parse on the same text somewhere else in your app
$template = $parser->parse($template, $data);
// Now that all parsing is done we inject the contents between the {{ noparse }} tags back into the template text
Lex\Parser::injectNoparse($template);
如果您只想解析数据数组而无需担心回调标签或注释,可以使用 parseVariables()
方法
$parser = new Lex\Parser();
$template = $parser->parseVariables(file_get_contents('template.lex'), $data);
模板中的 PHP
默认情况下,PHP 被编码,而不是执行。这是出于安全原因。然而,有时您可能想启用它。为此,只需将 true
作为 parse()
调用的第四个参数发送。
$parser = new Lex\Parser();
$template = $parser->parse(file_get_contents('template.lex'), $data, $callback, true);
语法
通用
所有Lex代码都由双大括号({{ }}
)分隔。这些分隔符的选择是为了减少与JavaScript和CSS冲突的可能性。
以下是一些Lex模板代码的示例
Hello, {{name}}
作用域粘合剂
作用域粘合剂是Lex用来触发作用域变化的字符。作用域变化发生在例如,你访问数组/对象中的嵌套变量,或者当你作用域自定义回调标签时。
默认情况下,点(.
)用作作用域粘合剂,尽管你可以选择任何字符。
设置作用域粘合剂
$parser->scopeGlue(':');
空白字符
分隔符前后允许有空白字符,但在某些情况下,标签内的空白字符是禁止的(以下章节将解释)。
一些有效示例
{{ name }}
{{name }}
{{ name}}
{{ name }}
{{
name
}}
一些无效示例
{{ na me }}
{ {name} }
注释
你可以通过将文本包裹在{{# #}}
中来给你的模板添加注释。
示例
{{# This will not be parsed or shown in the resulting HTML #}}
{{#
They can be multi-line too.
#}}
防止解析
你可以通过将代码包裹在{{ noparse }}{{ /noparse }}
标签中来防止解析器解析代码块。
示例
{{ noparse }}
Hello, {{ name }}!
{{ /noparse }}
变量标签
在处理变量时,你可以:访问单个变量,访问数组/对象中深层的嵌套变量,以及遍历数组。你甚至可以遍历嵌套数组。
简单变量标签
在我们的基本示例中,让我们假设你有以下变量数组(发送到解析器)
array(
'title' => 'Lex is Awesome!',
'name' => 'World',
'real_name' => array(
'first' => 'Lex',
'last' => 'Luther',
)
)
基本示例
{{# Parsed: Hello, World! #}}
Hello, {{ name }}!
{{# Parsed: <h1>Lex is Awesome!</h1> #}}
<h1>{{ title }}</h1>
{{# Parsed: My real name is Lex Luther!</h1> #}}
My real name is {{ real_name.first }} {{ real_name.last }}
{{ real_name.first }}
和{{ real_name.last }}
标签检查real_name
是否存在,然后检查first
和last
是否分别存在于real_name
数组/对象中,然后返回它。
循环变量标签
循环变量标签与简单变量标签类似,只是它们对应于数组数组的数组/对象,该数组被遍历。
循环变量标签是一个封闭标签,它包裹了循环的内容。关闭标签必须与打开标签完全匹配,但必须以正斜杠(/
)为前缀。正斜杠和标签名之间不能有空格(正斜杠之前允许有空格)。
有效示例
{{ projects }} Some Content Here {{ /projects }}
无效示例
{{ projects }} Some Content Here {{/ projects }}
循环内容是打开和关闭标签之间的内容。这个内容会遍历输出,对于循环数组中的每个项目都会执行。
当你在循环标签内时,你可以访问循环当前元素的任何子变量。
在以下示例中,让我们假设你有以下数组/对象变量
array(
'title' => 'Current Projects',
'projects' => array(
array(
'name' => 'Acme Site',
'assignees' => array(
array('name' => 'Dan'),
array('name' => 'Phil'),
),
),
array(
'name' => 'Lex',
'contributors' => array(
array('name' => 'Dan'),
array('name' => 'Ziggy'),
array('name' => 'Jerel')
),
),
),
)
在模板中,我们希望显示标题,然后是一个项目列表及其分配者。
<h1>{{ title }}</h1>
{{ projects }}
<h3>{{ name }}</h3>
<h4>Assignees</h4>
<ul>
{{ assignees }}
<li>{{ name }}</li>
{{ /assignees }}
</ul>
{{ /projects }}
正如你所看到的,在每个项目元素内部,我们可以访问该项目的分配者。你还可以看到,你可以遍历子值,就像你可以遍历任何其他数组一样。
条件语句
Lex中的条件语句简单易用。它允许使用标准的if
、elseif
和else
,但它还增加了unless
和elseunless
。
unless
和elseunless
与使用{{ if ! (expression) }}
和{{ elseif ! (expression) }}
完全相同。它们被添加为更简洁、更易于理解的语法。
所有if
块都必须用{{ endif }}
标签关闭。
条件语句中的变量不应使用标签分隔符(它会导致输出中出现奇怪的问题)。
条件语句可以包含你在PHP中使用的任何比较运算符(==
、!=
、===
、!==
、>
、<
、<=
、>=
)。你还可以使用任何逻辑运算符(!
、not
、||
、&&
、and
、or
)。
示例
{{ if show_name }}
<p>My name is {{real_name.first}} {{real_name.last}}</p>
{{ endif }}
{{ if user.group == 'admin' }}
<p>You are an Admin!</p>
{{ elseif user.group == 'user' }}
<p>You are a normal User.</p>
{{ else }}
<p>I don't know what you are.</p>
{{ endif }}
{{ if show_real_name }}
<p>My name is {{real_name.first}} {{real_name.last}}</p>
{{ else }}
<p>My name is John Doe</p>
{{ endif }}
{{ unless age > 21 }}
<p>You are to young.</p>
{{ elseunless age < 80 }}
<p>You are to old...it'll kill ya!</p>
{{ else }}
<p>Go ahead and drink!</p>
{{ endif }}
not运算符
not运算符等价于使用!
运算符。它们完全可互换(实际上not
在编译之前被翻译为!
)。
条件语句中的未定义变量
在条件语句中未定义的变量将被评估为 null
。这意味着你可以进行类似 {{ if foo }}
的操作,而不必担心变量是否已定义。
检查变量是否存在
要检查变量在条件语句中是否存在,请使用 exists
关键字。
示例
{{ if exists foo }}
Foo Exists
{{ elseif not exists foo }}
Foo Does Not Exist
{{ endif }}
你还可以将其与其他条件结合使用
{{ if exists foo and foo !== 'bar' }}
Something here
{{ endif }}
表达式 exists foo
的评估结果为 true
或 false
。因此,以下操作也是可行的
{{ if exists foo == false }}
{{ endif }}
条件语句中的回调标签
在条件语句中使用回调标签很简单。就像使用任何其他变量一样使用它,只有一个例外。当你需要为回调标签提供属性时,你必须用一对 单 个大括号将标签包围(你可以选择为所有回调标签使用它们)。
注意:当在条件语句中使用大括号时,在大括号之后或不带属性回调标签之前不能有任何空格。这样做会导致错误。
示例
{{ if user.logged_in }} {{ endif }}
{{ if user.logged_in and {user.is_group group="admin"} }} {{ endif }}
回调标签
回调标签允许你有属性标签,这些属性会被回调传递。这使得创建一个良好的插件系统变得容易。
以下是一个示例
{{ template.partial name="navigation" }}
你还可以关闭标签使其成为一个 回调块
{{ template.partial name="navigation" }}
{{ /template.partial }}
注意,属性不是必需的。当没有提供属性时,标签首先会被检查是否是数据变量,然后执行它作为回调。
{{ template.partial }}
回调
回调可以是任何有效的 PHP 可调用函数。它作为第三个参数发送到 parse()
方法。
$parser->parse(file_get_contents('template.lex'), $data, 'my_callback');
回调必须接受以下 3 个参数(按此顺序)
$name - The name of the callback tag (it would be "template.partial" in the above examples)
$attributes - An associative array of the attributes set
$content - If it the tag is a block tag, it will be the content contained, else a blank string
回调还必须返回一个字符串,该字符串将替换内容中的标签。
示例
function my_callback($name, $attributes, $content)
{
// Do something useful
return $result;
}
关闭回调标签
如果回调标签可以以单标签或块标签的形式使用,那么在使用它的单标签形式时,它必须被关闭(就像 HTML 中的那样)。
示例
{{ foo.bar.baz }}{{ /foo.bar.baz }}
{{ foo.bar.baz }}
Content
{{ /foo.bar.baz }}
自闭合回调标签
你可以使用自闭合标签来缩短上述内容,就像在 HTML 中一样。你只需在标签末尾放置一个 /
(/
和 }}
之间不能有空格)。
示例
{{ foo.bar.baz /}}
{{ foo.bar.baz }}
Content
{{ /foo.bar.baz }}
递归回调块
递归回调标签允许你循环访问具有与主块相同输出的子元素。它通过使用与数组键名一起的 recursive 关键字来触发。这两个单词必须用星号包围,如下面的示例所示。
示例
function my_callback($name, $attributes, $content)
{
$data = array(
'url' => 'url_1',
'title' => 'First Title',
'children' => array(
array(
'url' => 'url_2',
'title' => 'Second Title',
'children' => array(
array(
'url' => 'url_3',
'title' => 'Third Title'
)
)
),
array(
'url' => 'url_4',
'title' => 'Fourth Title',
'children' => array(
array(
'url' => 'url_5',
'title' => 'Fifth Title'
)
)
)
)
);
$parser = new Lex\Parser();
return $parser->parse($content, $data);
}
在模板中按以下方式设置。如果 children
不为空,Lex 将再次解析 {{ navigation }}
标签之间的内容,为 children
的每个数组。然后,生成的文本将插入到 {{ *recursive children* }}
的位置。这可以做到多层。
<ul>
{{ navigation }}
<li><a href="{{ url }}">{{ title }}</a>
{{ if children }}
<ul>
{{ *recursive children* }}
</ul>
{{ endif }}
</li>
{{ /navigation }}
</ul>
结果
<ul>
<li><a href="url_1">First Title</a>
<ul>
<li><a href="url_2">Second Title</a>
<ul>
<li><a href="url_3">Third Title</a></li>
</ul>
</li>
<li><a href="url_4">Fourth Title</a>
<ul>
<li><a href="url_5">Fifth Title</a></li>
</ul>
</li>
</ul>
</li>
</ul>