jacere/skhema

dev-master 2015-07-24 17:37 UTC

This package is not auto-updated.

Last update: 2024-09-28 18:00:03 UTC


README

Skhema是一个具有优雅和紧凑表示法的模板引擎,最初是为Bramble开发的。

语法

  • {@template}

    • 定义一个绑定源。
    • 可以定义在另一个模板中。内联模板在用法上没有限制。
    • 可以继承另一个模板。
    • 可以被另一个模板包含。
    • 根级别只允许模板。其他任何内容都是未定义的(被忽略或抛出异常)。
  • {$variable}

    • 用于通过数据绑定或模板继承填充的插槽。
    • 如果变量可用于绑定,但在绑定上下文中找不到值,则评估器将在放弃之前在根上下文中查找。这是处理全局变量的当前机制。
    • 如果变量从未获得值,则行为未定义(被忽略或抛出异常)。
    • 支持过滤器,允许调用已注册的用户定义函数。
  • {#include}

    • 内联包含另一个命名模板。
    • 如果找不到命名绑定,包含的模板将继承当前的绑定上下文。
    • 如果依赖关系图中存在循环,生成器将抛出异常。
  • {^extend}

    • 扩展另一个模板。
    • 一个模板最多可以扩展一个模板,并且此标记必须是第一个(忽略空白)。
    • 变量被继承,包括父模板中定义的任何值。
  • {.define}

    • 从继承的模板定义变量的内容。
    • 变量目前没有访问修饰符,因此没有无法定义(或重新定义)的私有变量。
  • {?source}

    • 绑定源,用于列表或仅用于更改绑定上下文。
    • 作为匿名模板实现,这些模板被转换为包含。
  • {/close}

    • 关闭当前作用域。
    • /之后的所有文本都是无关紧要的。
  • {%call}

    • 基本函数调用,目前只提供少量内置函数。
    • 可以像变量过滤器一样调用用户定义的函数。

用法

$manager = manager = TemplateManager::create((TEMPLATE_PATH);
$output = $manager->evaluate('Example', $data);

数据绑定

根命名绑定将应用于所有匹配的模板实例。目前尚无指定模板使用不能通过名称绑定的方法。我可能不会更改这一点,因为这将是非常糟糕的设计,在这种设计中可能会有这种情况。这种愚蠢的行为是不被允许的。

目前,绑定仍然非常基本。在Bramble MVC模式中,模型负责查询数据库并将结果转换为模板映射。以下代码片段显示了将查询结果映射到预期模板参数并将其分配给根命名绑定的一部分过程。

$posts_sql = '
	SELECT p.ID, p.Date, p.Title, p.Slug, p.Content, u.DisplayName FROM Posts p
	INNER JOIN Users u ON p.AuthorID = u.ID
	WHERE p.Type = 2
	AND p.Date BETWEEN :start AND :end
	ORDER BY p.Date DESC
';

$list[] = [
	'author'  => $row['DisplayName'],
	'date'    => date('Y-m-d', $time),
	'url'     => FormatURL($time, $row['Slug']),
	'title'   => $row['Title'],
	'content' => $row['Content'],
	'categories' => $categories,
];

return [
	'Posts' => [
		'title' => $title,
		'list' => $list
	]
];

函数和过滤器

函数和变量作为带有过滤器堆栈的评估标记实现,使用共享语法。可以在变量、函数和其他过滤器上堆叠过滤器。

{%cycle[white,LightGray]}
{%format-url[post]}
{%first[list/time]:format-date[atom]}
{$content:subvert[code,root,header=3]}

函数/过滤器需要注册,参数是过滤器选项、当前绑定上下文和输入值(对于过滤器)。任何适用的过滤器选项是过滤器处理器的责任。

$manager->register('format-date', function($options, $context, $date) {
	// return the formatted date using the specified options
});

示例

这是一个带有变量、内联模板定义、包含和绑定源的基模板。内联模板可能不是常见的做法,但它们的工作方式与包含的实例相同。在这种情况下,它们只是用来改变命名的绑定上下文。这里的{$content}变量是打算由继承的模板填充的。

{@TemplateBase}
<!DOCTYPE html>
<html>
<head>
	<title>{$title}</title>
</head>
<body>
	<div id="header">
		{@Header}
			<h1><a href="{$root-url}">jacere.net</a></h1>
			{@Navigation}
				<div id="nav">
					<ul>
						{?nav-list}
							<li><a href="{$url}">{$text}</a></li>
						{/?}
					</ul>
				</div>
			{/@}
		{/@}
	</div>

	<div id="content">
		{$content}
	</div>
	<div id="sidebar">
		{#Sidebar}
	</div>
</body>
</html>
{/@}

下面是一个继承此基模板以显示帖子列表的示例。这里的{$content}变量被定义为绑定源,这基本上是对命名数据上下文的循环。

{@Posts}
	{^TemplateBase}
	{.content}
		{?list}
			{#PostSection}
		{/?}
	{/.}
{/@}

{@PostSection}
<div class="article">
	<div class="title">
		<small>Posted by: <strong>{$author}</strong> | {$date}</small>
		<h2><a href="{$url}">{$title}</a></h2>
	</div>
	<div class="post">
		<div class="entry">
			{$content:subvert[code,root]}
		</div>
		<div class="postinfo">
			Posted in
			<ul class="taglist">
				{?categories}
					<li><a href="{$url}">{$name}</a></li>
				{/?}
			</ul>
		</div>
	</div>
</div>
{/@}

此示例显示了继承层次结构,其中每个模板扩展或定义了父模板的功能。

{@SidebarSection}
	<div class="right-sub-section" id="{$id}">
		<div class="title">
			<h2>{$title}</h2>
		</div>
		{$content}
	</div>
{/@}

{@SidebarSectionList}
	{^SidebarSection}
	{.content}
		<ul>
			{$list}
		</ul>
	{/.}
{/@}

{@SidebarSectionLinkList}
	{^SidebarSectionList}
	{.list}
		{?list}
			<li><a href="{$url}" title="{$text}">{$text}</a></li>
		{/?}
	{/.}
{/@}

{@SidebarSectionRecent}
	{^SidebarSectionLinkList}
	{.id}recent-posts{/}
	{.title}Recent Posts{/}
{/@}

许可证

本项目根据MIT许可证的条款进行许可。