wernerwa / pat-template
patTemplate 是一个功能强大的非编译模板引擎,它使用 XML 标签将文档分成不同的部分。
Requires
- php: >=5.3
- pear/pear-core-minimal: ^1.0
- wernerwa/pat-error: ^1.1
Suggests
- pear/xul: ^0.9.1
README
patTemplate 帮助您将业务逻辑与网站的布局和内容分离。
使用 patTemplate,您将不再直接在 HTML 代码中嵌入 PHP 代码。相反,您将在 HTML 文档中插入占位符,这些占位符将由您的 PHP 应用程序计算的实际值替换。
维基在 https://web.archive.org/web/20150505033634/http://trac.php-tools.net/patTemplate/wiki/Docs 存档
patTemplate 与 PHP 5.1-8.3 兼容
patTemplate 供设计师使用
patTemplate 提供基于 XML 的标记标签,以便访问布局文件的各个部分,您可以隐藏、交换或重复部分。这意味着,您的 HTML 设计师需要学习一些新的标签及其用法。然而,他们不需要学习一种新的编程语言。与其他模板引擎不同,patTemplate 采用声明性方法处理模板标签,您在模板中找不到任何 if/else
语句或 for
循环。
patTemplate 供开发者使用
如果您的设计师熟悉 patTemplate 语法,您将需要学习 patTemplate 的 PHP-API,以便将占位符的实际值分配给模板。如果您是经验丰富的 PHP 开发者,您将轻松掌握 API,因为您不需要学习很多新方法。
入门
patTemplate 允许您将页面分成几个称为 模板 的块。它要求您至少指定一个包含完整页面的块,即 根 模板。在这个模板内部,您可以嵌套任意多的模板。每个模板都应该有一个唯一的名称,以便可以从您的 PHP 应用程序中访问它。要标记页面中的模板,您需要将 HTML 代码包围在 <patTemplate:tmpl/>
标签中
<patTemplate:tmpl name="page"> This is the main page. <patTemplate:tmpl name="foo"> It contains another template. </patTemplate:tmpl> <patTemplate:tmpl name="bar"> And one more. </patTemplate:tmpl> </patTemplate:tmpl>
从文件加载此模板很容易。您只需要创建一个新的 patTemplate
实例,并将文件名传递给 readTemplatesFromInput
方法
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-templates.tmpl');
patTemplate 现在将打开文件 my-templates.tmpl 并扫描其中的 <patTeamplate:tmpl/>
标签。它将创建如下结构
+ page
+ foo
+ bar
如果您想将 HTML 内容发送到浏览器,您需要调用 displayParsedTemplate()
方法,并传递要显示的模板的名称
$tmpl->displayParsedTemplate('page');
在解析和显示模板时,所有嵌套的模板都将被显示。因此,调用此方法将显示
This is the main page.
It contains another template.
And one more.
如果您不想输出 HTML 代码,而是将其存储在 PHP 变量中,您可以调用 getParsedTemplate()
代替。如果您不向 displayParsedTemplate()
或 getParsedTemplate()
传递模板的名称,patTemplate 将显示根模板(即创建 patTemplate 对象后读取的第一个模板)。
为模板选择目录
您肯定不会将模板文件放在网站空间的根目录中,而是放在名为 templates 或类似名称的文件夹中。如果您不希望在每次调用 readTemplatesFromInput()
时指定文件的完整路径,您可以使用 setRoot()
方法
$tmpl = new patTemplate(); $tmpl->setRoot('/path/to/templates'); $tmpl->readTemplatesFromInput('my-template.tmpl');
此示例将从文件 /path/to/templates/my-template.tmpl 加载模板。
以下页面将向您展示如何在页面中添加变量或使用不同的模板类型。
向模板添加变量
变量是模板中的占位符,您可以从PHP应用程序中为其分配任何值。
在patTemplate中有两种类型的变量:
- 局部变量,仅在添加变量的模板中可用
- 全局变量,在所有模板中可用
要在模板中放置变量,需要将变量用大括号括起来。变量只能由大写字母、数字、破折号和下划线组成
<patTemplate:tmpl name="page"> Hello {NAME}.<br/> </patTemplate:tmpl>
此模板包含一个名为}的变量,您可以从应用程序为其分配值。
使用addVar()添加局部变量
在添加局部变量时,必须使用addVar()
方法,并传递要添加变量的模板的名称、变量的名称以及要分配的值
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-template.tmpl'); $tmpl->addVar('page', 'NAME', 'Stephan'); $tmpl->displayParsedTemplate();
此脚本将显示:
Hello Stephan.
除了字符串之外,您还可以传递一个包含多个值的数组。在这种情况下,patTemplate将重复分配变量的模板,对于数组中的每个条目重复一次。只需更改一行代码即可添加多个名称
$tmpl->addVar('page', 'NAME', array('Stephan', 'Sebastian'));
现在该脚本将显示:
Hello Stephan.
Hello Sebastian.
无需在您的PHP应用程序或模板文件中创建for循环。
使用addVars()一次添加多个变量
模板不仅包含一个变量,还可以包含您想要的任意多个变量
<patTemplate:tmpl name="page"> {GREETING} {NAME}.<br/> </patTemplate:tmpl>
除了对addVar()
进行两次调用之外,您还可以将关联数组传递给addVars()
方法
$vars = array( 'GREETING' => 'Guten Tag', 'NAME' => 'Stephan' ); $tmpl->addVars('page', $vars);
这将向模板page添加两个变量(GREETING和NAME)并显示
Guten Tag Stephan.
使用addVars()
也可以为变量分配多个值
$vars = array( 'GREETING' => array('Guten Tag', 'Bonjour'), 'NAME' => array('Stephan', 'Sebastian') ); $tmpl->addVars('page', $vars);
这将显示:
Guten Tag Stephan.
Bonjour Sebastian.
如果您将数组分配给一个变量,将字符串分配给另一个变量,patTemplate将为每个迭代使用相同的字符串
$vars = array( 'GREETING' => 'Hello', 'NAME' => array('Stephan', 'Sebastian') ); $tmpl->addVars('page', $vars);
此示例将显示:
Hello Stephan.
Hello Sebastian.
使用addRows()添加变量行
通常,您会遇到以下结构的记录集:
$data = array( array('name' => 'Stephan Schmidt', 'id' => 'schst'), array('name' => 'Sebastian Mordziol', 'id' => 'argh'), array('name' => 'Gerd Schaufelberger', 'id' => 'gerd') );
如果您想创建一个包含此信息的HTML表格,可以使用addRows()
方法和以下模板
<patTemplate:tmpl name="page"> <table> <tr> <th>User-Id</th> <th>Name</th> </tr> <patTemplate:tmpl name="entry"> <tr> <td>{USER_ID}</td> <td>{USER_NAME}</td> </tr> </patTemplate:tmpl> </table> </patTemplate:tmpl>
此页面由两个模板组成,根模板(page)和应针对数组中的每个记录集重复的模板(entry)。要构建包含所有记录集的列表,只需调用一个方法即可
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-template.tmpl'); $tmpl->addRows('entry', $data, 'USER_'); $tmpl->displayParsedTemplate();
此方法接受三个参数:
- 模板的名称
- 包含所有记录集的数组
- 变量名称的可选前缀
此方法非常适合创建数据库结果集的列表,如由PEAR DB的getAll()方法返回的列表。
使用addObject()添加对象
除了使用关联数组之外,您还可以使用对象。
假设您正在使用以下类在应用程序中:
class User { public $id; public $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } }
并且您创建了一个用于显示用户信息的模板
<patTemplate:tmpl name="user-info"> <table> <tr> <th>Id:</th> <td>{USER_ID}</td> </tr> <tr> <th>Name:</th> <td>{USER_NAME}</td> </tr> </table> </patTemplate:tmpl>
现在您可以直接将User
类的实例传递到模板中
$schst = new User('schst', 'Stephan Schmidt'); $tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('user-info.tmpl'); $tmpl->addObject('user-info', $schst, 'USER_');
这将显示:
Id: schst
Name: Stephan Schmidt
patTemplate将提取所有标记为public
的属性,并将它们添加到指定的模板中,并在前面加上您在addRows()
示例中看到的前缀。如果您不想将属性声明为public
,您也可以在类中实现一个getVars()
方法,该方法返回一个包含要添加到模板的变量的关联数组
class User { private $id; private $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } /** * This method will be invoked by patTemplate if the * object is passed to addObject() */ public function getVars() { return array( 'id' => $this->id, 'name' => $this->name ); } }
结果将完全相同。
使用addGlobalVar()和addGlobalVars()添加全局变量
如果您想在页面上的每个模板块中使用一个变量,使用上述任何一种方法将变量添加到每个模板中可能会变得很繁琐。相反,您可以使用 addGlobalVar()
或 addGlobalVars()
方法将变量添加到页面上 每个 模板中。
现在,您可以在所有模板中使用变量 {NOW}
局部变量和全局变量方法之间有两个区别
- 全局方法 不需要 将模板名称作为第一个参数。
- 全局方法 不接受 数组作为变量的值。
如果变量名在全局和局部中都使用,则局部变量具有优先级。
进一步阅读
有关变量的更多信息,您可以阅读
设置变量的默认值
当使用 <patTemplate:var/>
标签将变量包含在模板中时,您可以指定一个默认值,该值将在从 PHP 没有分配值给此变量时使用。这可以通过使用 default
属性来实现。
<patTemplate:tmpl name="page"> Hello <patTemplate:var name="user" default="Guest"/>. </patTemplate:tmpl>
只要没有为变量 user
分配值,此页面将显示
Hello Guest.
使用函数的返回值
自修订版 [438](或 patTemplate 3.1.0a3)以来,您可以指定一个 PHP 函数或静态方法,该函数或静态方法将用于生成变量的默认值。同样,可以使用 default
属性。
<patTemplate:tmpl name="page">
The current time is <patTemplate:var name="timestamp" default="time()"/>.
</patTemplate:tmpl>
这样,您可以在不编写 PHP 代码的情况下包含当前的 UNIX 时间戳。由于这存在安全风险(您的模板设计人员可以调用任何 PHP 函数),您必须启用此功能,以便可以在模板中使用它。
$tmpl = new patTemplate(); $tmpl->setOption('allowFunctionsAsDefault', true);
要调用静态方法而不是函数,您需要指定类名和方法名,方法名之间用两个冒号分隔。
<patTemplate:tmpl name="page"> The current time is <patTemplate:var name="timestamp" default="MyClass::getTime()"/>. </patTemplate:tmpl>
函数和方法将在从文件读取模板时进行评估。您无法从该函数访问变量的值。这正是应该使用 变量修饰符 的原因。
从其他模板访问变量
在以下两种情况下,您可能希望从任何其他模板访问变量
- 显示变量的值
- 将值用作条件模板的条件
在这两种情况下,您都可以使用 点语法 来解决问题。
从其他模板导入变量
要将不同模板中的一个变量导入当前模板,您必须使用具有 copyFrom
属性的 <patTemplate:var/>
标签。
PHP 代码
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('myPage.tmpl'); $tmpl->addVar('header', 'TITLE', 'Page title'); $tmpl->displayParsedTemplate();
模板
<patTemplate:tmpl name="page"> <patTemplate:tmpl name="header"> <head> <title>{TITLE}</title> </head> </patTemplate:tmpl> <patTemplate:tmpl name="footer"> <div> <small><patTemplate:var name="copiedVar" copyFrom="header.TITLE"/></small> </div> </patTemplate:tmpl> </patTemplate:tmpl>
在上面的示例中,我们将从模板 header
导入变量 TITLE
到模板 footer
中,并将导入的值命名为 copiedVar
。我们还可以对复制的变量应用一个 变量修饰符。自修订版 [437] 以来,也可以使用 __parent.VARNAME
来从父模板获取任何变量,而无需指定模板的名称。
在条件中使用点语法
当创建 条件模板 时,您可以在 conditionVar
属性中使用 点语法。
<patTemplate:tmpl name="page"> <patTemplate:tmpl name="header"> <head> <title>{TITLE}</title> </head> </patTemplate:tmpl> <patTemplate:tmpl name="footer" type="condition" conditionVar="header.TITLE"> <patTemplate:sub condition="Homepage"> Display on the homepage. </patTemplate:sub> <patTemplate:sub condition="__default"> Display on all other pages. </patTemplate:sub> </patTemplate:tmpl> </patTemplate:tmpl>
现在,footer
模板的输出将取决于您分配给 header
模板的变量 TITLE
的值。
创建模板
patTemplate 允许您将页面分成几个称为 模板 的块。它要求您至少指定一个包含完整页面的块,即 根 模板。在这个模板内部,您可以嵌套任意多的模板。每个模板都应该有一个唯一的名称,以便可以从您的 PHP 应用程序中访问它。要标记页面中的模板,您需要将 HTML 代码包围在 <patTemplate:tmpl/>
标签中
<patTemplate:tmpl name="page"> This is the main page. <patTemplate:tmpl name="foo"> It contains another template. </patTemplate:tmpl> <patTemplate:tmpl name="bar"> And one more. </patTemplate:tmpl> </patTemplate:tmpl>
从文件加载此模板很容易
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-templates.tmpl');
patTemplate 现在将打开文件 my-templates.tmpl 并扫描其中的 <patTeamplate:tmpl/>
标签。它将创建如下结构
+ page
+ foo
+ bar
如果您想将 HTML 内容发送到浏览器,您需要调用 displayParsedTemplate()
方法,并传递要显示的模板的名称
$tmpl->displayParsedTemplate('page');
在解析和显示模板时,所有嵌套的模板都将被显示。因此,调用此方法将显示
This is the main page.
It contains another template.
And one more.
如果您不想输出 HTML 代码,而是将其存储在 PHP 变量中,您可以调用 getParsedTemplate()
代替。如果您不向 displayParsedTemplate()
或 getParsedTemplate()
传递模板的名称,patTemplate 将显示根模板(即创建 patTemplate 对象后读取的第一个模板)。
为模板选择目录
您肯定不会将模板文件放在网站空间的根目录中,而是放在名为 templates 或类似名称的文件夹中。如果您不希望在每次调用 readTemplatesFromInput()
时指定文件的完整路径,您可以使用 setRoot()
方法
$tmpl = new patTemplate(); $tmpl->setRoot('/path/to/templates'); $tmpl->readTemplatesFromInput('my-template.tmpl');
此示例将从文件 /path/to/templates/my-template.tmpl 加载模板。
patTemplate 允许您不仅从文件系统读取模板,还可以从任何数据源读取模板。
进一步阅读
当然,这并不是 patTemplate 提供的全部功能。patTemplate 提供不同类型的模板,这些模板具有不同的功能。
- 简单条件模板允许您模拟
if
语句。 - 条件模板允许您模拟
if/else
和switch/case
语句。 - 模版模板允许您创建表示交替列表的模板。
除了 tmpl
标签之外,还有 [wiki:Docs/TagReference 多个其他标签],甚至可以 [wiki:Docs/Developer/CustomFunctions 创建自己的标签]。
简单条件模板!
几乎在每一个应用中,都会有前端 HTML 的部分,只有在某些信息可用时才应该显示。一个例子可以是显示当前登录用户信息的框。如果没有任何用户登录,显示这个框就没有意义。
通过提供简单条件模板,patTemplate 帮助您实现这一点。
请看以下模板
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="user-info"> <div id="userInfo"> Logged in as {USER_NAME} ({USER_ID}). </div> </patTemplate:tmpl> </patTemplate:tmpl>
要将用户信息添加到该页面,您需要使用 addVars()
方法,如下代码片段所示
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-template.tmpl'); if (userIsLoggedIn()) { $user = array( 'ID' => getUserId(), 'NAME' => getUserName() ); $tmpl->addVars('user-info', $user, 'USER_'); }
问题是,如果没有用户登录,用户信息框的 HTML 代码仍然会显示。这可以通过向 <patTemplate:tmpl/>
标签添加两个属性来轻松更改。
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="user-info" type="simpleCondition" requiredVars="USER_ID"> <div id="userInfo"> Logged in as {USER_NAME} ({USER_ID}). </div> </patTemplate:tmpl> </patTemplate:tmpl>
将 type
属性设置为 simpleCondition
将模拟一个 if
条件。属性 requiredVars
允许您指定一个变量,该变量必须分配一个非空值才能显示模板。将此属性设置为 USER_ID
可以强制该模板在未传递用户 ID 时隐藏。
指定多个变量
也可以指定多个变量。在这种情况下,您必须将属性值设置为一个以逗号分隔的变量名列表。如果任何变量具有非空值,则模板将显示。
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="user-info" type="simpleCondition" requiredVars="USER_ID,USER_NAME"> <div id="userInfo"> Logged in as {USER_NAME} ({USER_ID}). </div> </patTemplate:tmpl> </patTemplate:tmpl>
在这个例子中,如果已设置用户名或用户 ID,则用户信息框将显示。
使用全局变量
如果您想在模板的不同位置显示用户 ID 和用户名,您可能想添加全局变量。
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-template.tmpl'); if (userIsLoggedIn()) { $user = array( 'ID' => getUserId(), 'NAME' => getUserName() ); $tmpl->addGlobalVars($user, 'USER_'); }
默认情况下,简单条件模板会检查变量是否已被 局部 分配。这可以通过将 useGlobals
属性设置为 true
来更改。
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="user-info" type="simpleCondition" requiredVars="USER_ID" useGlobals="true"> <div id="userInfo"> Logged in as {USER_NAME} ({USER_ID}). </div> </patTemplate:tmpl> </patTemplate:tmpl>
指定一个必需的值
不仅可以检查变量是否具有非空值,还可以检查是否已将特定值分配给变量。请看以下模板
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="admin-options"> <div id="userInfo"> Admin-Options:<br/> - Delete page<br/> - Edit page<br/> </div> </patTemplate:tmpl> </patTemplate:tmpl>
模板 admin-options 应仅在当前登录用户是管理员时显示。因此,我们更改 PHP 代码,将此信息全局传递给模板。
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('my-template.tmpl'); if (userIsLoggedIn()) { $user = array( 'ID' => getUserId(), 'NAME' => getUserName(), 'TYPE' => getUserType() ); $tmpl->addGlobalVars($user, 'USER_'); }
getUserType()
函数应根据当前登录用户的状态返回 admin
或 user
。因此,仅检查 USER_TYPE
变量是否设置是不够的,您需要检查它是否设置为 admin
。这可以很容易地完成。
<patTemplate:tmpl name="page"> Here is your main content. <patTemplate:tmpl name="admin-options" type="simpleCondition" requiredVars="USER_TYPE=admin"> <div id="userInfo"> Admin-Options:<br/> - Delete page<br/> - Edit page<br/> </div> </patTemplate:tmpl> </patTemplate:tmpl>
此功能可以与之前讨论的功能结合使用,该功能允许您指定多个必需变量。
条件模板
简单条件模板允许您在没有else块的条件下模拟简单的if语句。如果这不足以满足您的任务,您可能会发现条件模板很有用。它允许您在模板中包含完整的switch/case块。
预定义条件
使用变量作为条件
向模板中添加注释
如果您的模板变得复杂,您可能想记录您正在做的事情,以便其他开发人员或设计师更容易理解模板结构。当然,您可以直接在模板中添加简单的HTML注释,但这些会在显示页面时发送到浏览器,这会导致额外的流量,尽管客户端并不需要这些信息。
为了避免这种情况,patTemplate提供了<patTemplate:comment/>
标签。当页面显示时,此标签内的所有数据都将被忽略
<patTemplate:tmpl name="page"> <patTemplate:comment> You may place any content here, that documents the page template. </patTemplate:comment> Content of the template goes here... </patTemplate:tmpl>
在读取和显示此模板时,结果将是
Content of the template goes here...
使用注释标签的优点之一。尽管注释标签内的数据不会显示,但patTemplate会读取并解释它。当使用dump()方法调试模板时,注释将显示在包含它们的模板旁边。
使用选项
patTemplate允许您通过设置其选项来影响其行为。要设置选项,可以使用setOption方法。它接受两个参数
- 选项的名称
- 选项的值
示例
$tmpl = new patTemplate(); $tmpl->setOption('allowFunctionsAsDefault', true);
可用的选项
以下表格显示了所有可用的选项
|| 选项 || 描述 || 可能的值 || || maintainBc || patTemplate是否应维持与2.x版本的向后兼容性。如果设置为true
,您可以在<patTemplate:sub/>
标签中使用empty和default而不是!__empty和!__default || true
或false
|| || defaultFunction || 应该调用的模板函数(即用户定义的标签)的名称 || 任何字符串 || || allowFunctionsAsDefault || 是否允许将PHP函数指定为变量的默认值。 || true
或false
||
高级功能
patTemplate不仅限于在HTML模板中替换占位符。
在这里,您可以找到有关更复杂功能的教程
- [wiki:Docs/Advanced/Modifiers 变量修改器]
- [wiki:Docs/Advanced/TemplateCache 使用模板缓存提高性能]
- [wiki:Docs/Advanced/OutputFilters 输出过滤器]
- [wiki:Docs/Advanced/InputFilters 输入过滤器]
- [wiki:Docs/Advanced/External 包含外部模板]
从各种数据源读取模板
patTemplate不仅限于从文件系统读取模板,而是采用基于驱动的方法从几乎任何地方读取模板。
这种基于驱动的方法有两个优点
- 可以从任何数据源读取模板
- 不同的驱动程序可以解析不同的模板格式
读取模板的驱动程序称为模板读取器。目前,以下[源:trunk/patTemplate/Reader/读取器]是可用的
- String,从字符串中读取模板,当模板在运行时创建时可以使用。
- File,从一个或多个文件中读取模板。这是默认读取器。
- DB,从由[http://pear.php.net/package/DB PEAR::DB]支持的任何数据库中读取模板
- IT,从文件系统中以[http://pear.php.net/package/HTML_Template_IT HTML_Template_IT]格式读取模板
在调用parseTemplatesFromInput()时可以指定要使用的读取器
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('MyTemplates.tmpl', 'File');
如果想要使用文件读取器,读取器名称是可选的。
从文件中读取模板
从文件中读取模板是最常见的任务。您可以使用setRoot()方法指定一个或多个模板所在的文件夹。
$tmpl = new patTemplate(); $tmpl->setRoot('/path/to/templates', 'File'); $tmpl->readTemplatesFromInput('myTemplate.tmpl');
从字符串中读取模板
从字符串中读取模板可能很有用,当你需要从一个patTemplate不支持且实现新读取器过于繁琐的源中读取模板时。
你所需要做的就是将模板源传递给readTemplatesFromInput()
方法
$string = '<patTemplate:tmpl name="string">This template has been parsed from a string `<patTemplate:tmpl name="too">`, as well as this.</patTemplate:tmpl></patTemplate:tmpl>'; $tmpl = new patTemplate(); $tmpl->readTemplatesFromInput( $string, 'String' );
从数据库中读取模板
当从数据库中读取模板时,将使用[http://pear.php.net/package/DB PEAR::DB]抽象层。你需要将[http://pear.php.net/manual/en/package.database.db.intro-dsn.php DSN]字符串传递给setRoot()
方法
tmpl = new patTemplate(); $tmpl->setRoot('mysql://root:@localhost/test', 'DB');
假设,你的模板存储在一个名为templates的表中,该表有两个字段
id
,模板的唯一IDcontent
,包含实际模板的文本字段
如果你想从数据库中读取名为foo的模板,你可以使用两种不同的方法。一种是将SQL语句传递给readTemplatesFromInput()
方法
$tmpl->readTemplatesFromInput("SELECT content FROM templates WHERE id='foo'", 'DB');
但是,如果你的表非常简单,你可以让读取器为你构建查询,并使用类似于XPath的语法
$tmpl->readTemplatesFromInput('templates[@id=foo]/@content', 'DB');
该字符串由以下部分组成
$table[@$keyName=$keyValue]/@$templateField
读取HTML_Template_IT模板
IT读取器允许你使用[http://pear.php.net/manual/en/package.html.html-template-it.intro.php HTML_Template_IT或PHPLib]语法读取模板。读取器本身的工作方式与File读取器完全相同。
使用变量修改器
变量修改器允许模板设计者在浏览器显示之前修改从PHP传递过来的值。
想象以下PHP脚本
<?php $tmpl = new patTemplate(); $tmpl->setRoot('templates'); $tmpl->readTemplatesFromInput('modifier.tmpl'); $tmpl->addVar( 'page', 'multiline', 'This contains some line breaks...' ); $tmpl->addVar( 'page', 'birthday', '1974-05-12' ); $tmpl->displayParsedTemplate();
业务逻辑将两个值添加到模板中,但它们都有相当大的问题
multiline
变量包含HTML中不可见的换行符birthday
变量可能没有首选的格式。
这两个问题都可以在模板中单独解决
<patTemplate:tmpl name="page"> Apply a modifier to multiline: <patTemplate:var name="multiline" modifier="nl2br" modifierType="php"/> Dateformat modfifier:<br /> <patTemplate:var name="birthday" modifier="dateformat" format="%d.%m.%Y"/> </patTemplate:tmpl>
可以使用两种方式使用变量修改器
- 你可以指定任何接受字符串作为其唯一参数并返回值的PHP函数。返回的值将用作模板中的值。
- 你可以使用patTemplate发行版提供的任何提供的修改器。查看[源:trunk/patTemplate/Modifier/ patTemplate/Modifier]目录,了解我们提供的修改器。
如果发行版中包含的任何修改器都无法解决问题,你可以轻松[wiki:Docs/Developer/Modifiers编写新的修改器]。
使用多个修改器
从版本3.1.0a2开始,也可以使用多个修改器,通过指定逗号分隔的函数列表来实现。
使用短修改器语法
如果你熟悉Smarty模板引擎,你可能会更喜欢他们指定变量修改器的语法。patTemplate提供了一个输入过滤器,允许你使用相同的语法。它可以轻松启用
$tmpl = new patTemplate(); $tmpl->applyInputFilter('ShortModifiers');
你可以按照以下方式指定变量修改器
<patTemplate:tmpl name="page"> Apply a modifier to multiline: {MULTILINE|nl2br} Dateformat modfifier:<br /> {BIRTHDAY|Dateformat|format:%d.%m.%Y} </patTemplate:tmpl>
使用模板缓存
当使用模板缓存时,patTemplate不需要在每次请求时都对模板源应用正则表达式,而是缓存读取器的结果。
使用模板缓存非常简单
$tmpl = new patTemplate(); $tmpl->setRoot('templates'); $tmpl->useTemplateCache('File', array( 'cacheFolder' => './tmplCache', 'lifetime' => 10, 'filemode' => 0644 ) ); $tmpl->readTemplatesFromInput('myTemplate.tmpl'); $tmpl->displayParsedTemplate();
以下缓存可用
- 文件
- MMCache
- eAccelerator
这些缓存中的每一个都有不同的选项,请参阅缓存的API文档,了解支持的参数。
缓存是如何工作的
启用缓存时,patTemplate会将从文件中读取的所有模板的序列化数组存储在缓存中。下次您调用readTemplatesFromInput()
时,patTemplate将首先检查是否存在缓存的版本,而不是从文件中读取模板并评估所有包含的标签。
模板缓存不会缓存您页面的输出。
使用输出过滤器
输出过滤器可用于透明地修改patTemplate生成的HTML结果。输出过滤器可以应用于单个模板或调用displayParsedTemplate()
时显示的完整HTML。
对生成的页面使用输出过滤器
要将对所有生成内容应用任何输出过滤器,您可以使用接受以下参数的applyOutputFilter()
方法:
- 过滤器名称
- 包含选项的可选关联数组
以下示例将应用Tidy输出过滤器(需要ext/tidy
),它可用于创建更干净的HTML:
$tmpl = new patTemplate(); $options = array( 'output-xhtml' => true, 'clean' => true ); $tmpl->applyOutputFilter('Tidy', $options); $tmpl->readTemplatesFromInput('myPage.tmpl'); $tmpl->displayParsedTemplate();
您可以应用多个输出过滤器,它们将按应用顺序执行。
关于getParsedTemplate()呢?
当使用getParsedTemplate()
时,除非您将第二个参数提供为true
,否则输出过滤器将不会应用。
$tmpl = new patTemplate(); $tmpl->setRoot('templates'); $tmpl->applyOutputFilter('StripWhitespace'); $tmpl->readTemplatesFromInput('myPage.tmpl'); // Will not strip whitespace $html = $tmpl->getParsedTemplate('page'); // Will strip whitespace $compressed = $tmpl->getParsedTemplate('page', true);
仅对一个模板应用输出过滤器
如果您只想将输出过滤器应用于单个模板,可以使用<patTemplate:tmpl/>
标签的outputFilter
属性。
<patTemplate:tmpl name="page" outputFilter="StripWhitespace"> The whitespace will alyways be stripped from this template. </patTemplate:tmpl>
无论是否使用displayParsedTemplate()
或getParsedTemplate()
,过滤器都将应用于此模板。
可用的过滤器
以下过滤器包含在发行版中
BBCode
,使用[http://trac.php-tools.net/patBBCode patBBCode]将模板中的BBCode转换为HTMLGZip
,用于在将页面发送到浏览器之前对页面进行gzip压缩(由于明显的原因,不能仅用于单个模板)HighlightPhp
,用于在模板中对PHP代码进行语法高亮显示(使用[https://php.ac.cn/manual/en/function.highlight-string.php highllight_string()])PdfLatex
,用于将LaTeX文档转换为PDF(可用于使用patTemplate生成PDF)StripWhitespace
,用于从文档中删除不需要的空白字符Tidy
,用于使用[https://php.ac.cn/manual/en/ref.tidy.php tidy扩展]修复HTML。
所有输出过滤器都位于[source:trunk/patTemplate/OutputFilter/ patTemplate/OutputFilter/]文件夹中。您还可以轻松[wiki:Docs/Developer/OutputFilters实现新的过滤器]。
使用输入过滤器
输入过滤器应用于模板文件的内容在读取器分析标签之前。这使得您能够修改原始HTML代码并动态插入由模板引擎解释的patTemplate标签或变量。
使用输入过滤器非常简单,您只需要将过滤器的名称传递给applyInputFilter()
方法。
$tmpl->applyInputFilter('StripComments');
StripComments
输入过滤器将在patTemplate分析之前从文件中删除所有HTML和JavaScript注释。这有两个优点:
- 读取器更快,因为要解析的HTML代码更少。
- 您可以在
<patTemplate:tmpl>
和<patTemplate:sub>
标签之间插入HTML注释。patTemplate不允许在这些标签之间有任何字符数据,但由于数据在patTemplate解析文件之前被删除,它不会对此进行投诉。
目前patTemplate提供了两个输入过滤器
- 使用[browser:/trunk/patTemplate/InputFilter/StripComments.php StripComments]移除HTML和JavaScript注释
- 使用[browser:/trunk/patTemplate/InputFilter/ShortModifiers.php ShortModifiers]可以使用从Smarty中已知的简写变量修饰符语法
所有输入过滤器都位于[browser:/trunk/patTemplate/InputFilter InputFilter]文件夹中,您可以轻松[wiki:Docs/Developer/InputFilters实现新的输入过滤器]。
包含外部模板
patTemplate允许您将模板拆分为更小的文件,以便在多个页面中重用模板。想象一下,您有一个存储在header.tmpl中的页面标题模板。
<patTemplate:tmpl name="header"> Here goes the header of your page... </patTemplate:tmpl>
现在,您想在显示页面的模板中重用此模板。这可以通过使用带有src
属性的<patTemplate:tmpl/>
标签来实现
<patTemplate:tmpl name="page"> <patTemplate:tmpl name="header_include" src="header.tmpl" parse="on"/> The rest of the page goes here. </patTemplate:tmpl>
现在您可以像加载普通模板一样加载页面模板
$tmpl = new patTemplate(); $tmpl->readTemplatesFromInput('page.tmpl');
加载的模板结构现在是
+ page
+ header_include
+ header
如您所见,header
模板被处理,就像包含此模板的标签嵌套在header_include
模板中一样。这意味着,您也可以向header
模板分配变量,就像它是一个包含在page.tmpl中的普通模板一样。
包含标准HTML
使用相对路径包含
在运行时更改源
更改命名空间
patTemplate不会强制您将所有标签都放在pat
命名空间内。可以通过调用setNamespace()
方法轻松更改前缀
$tmpl->setNamespace('MyNamespace');
您还可以指定多个前缀
$tmpl->setNamespace(array('MyNamespace', 'pat'));
如果您查看Joomla!,您会看到他们已将默认命名空间更改为mos
,但标签却是完全相同的。
patTemplate标签参考
所有patTemplate标签都必须放在patTemplate命名空间内,并且因此使用patTemplate
前缀,除非您[wiki:Docs/Advanced/Namespace更改命名空间]。因此,每个标签都必须像以下示例中的那样
<patTemplate:tmpl name="foo"> some content </patTemplate:tmpl>
所有标签和属性名称都是不区分大小写的。
“tmpl”标签
<patTemplate:tmpl/>
标签是patTemplate的主要标签。它用于标记模板中的一个块,该块可以从您的PHP脚本中访问。
属性
必需的属性包括
name
:模板的唯一名称
可选属性包括
addsystemvars
:标志,指示是否应将系统变量添加到模板。可能的值是boolean
、integer
或off
autoclear
:标志,指示模板是否应在解析多次时清除。autoload
:标志,指示外部模板是否应自动加载或仅在请求时加载。只能用于已设置src
属性的情况。conditionVar
:子模板中将进行测试的变量的名称(仅适用于type="condition"
)defaultModifier
:应用于模板中所有变量的默认[wiki:Docs/Advanced/Modifiers变量修饰符]的名称。loop
:不考虑是否有足够的数据分配给变量,最小重复次数。limit
:限制重复次数。语法与MySQL的LIMIT
语句相同。maxloop
:限制模板的最大重复次数。如果有更多数据可用,父模板将被重复。modulo
:要使用的模数。仅当type="modulo"
时可用。outputfilter
:应用于此模板的[wiki:Docs/Advanced/OutputFilters输出过滤器]的名称。parse
:标志,指示在src
中引用的外部文件是否包含patTemplate标签(yes
)或不包含(no
)(只能与src
一起使用)reader
:用于解析外部模板的读取器的名称。只能与src
一起使用。relative
:标志,指示在src
中的文件名是否相对于当前文件(yes
)或不是(no
)(只能与src
一起使用)requiredvars
: 必须设置的变量列表,以逗号分隔,以便模板显示。仅与type="simpleCondition"
结合使用。rowoffset
: {PAT_ROW_VAR} 变量的起始数字。src
: 包含此模板内容(如果为外部)的文件。type
: 模板类型(standard
、condition
、simpleCondition
)、OddEven
或modulo
。unusedvars
: 未分配值的变量将应用的默认行为。可能的值是strip
、ignore
、comment
或nbsp
。useglobals
: 标志,表示是否应在条件中检查全局变量。仅当type
设置为condition
或simpleCondition
时使用。varscope
: 变量将从中导入的其它模板列表,以逗号分隔。visibility
: 模板的可见性。可能的值是visible
或hidden
。whitespace
: 将应用于模板的空白处理。可能的值是keep
或trim
。
示例
<patTemplate:tmpl name="foo"> some content </patTemplate:tmpl>
"sub" 标签
<patTemplate:sub/>
标签在 <patTemplate:tmpl/>
标签内使用,如果其 type
属性设置为 condition
、OddEven
或 modulo
。它用于定义依赖于不同条件的内容。
属性
必需的属性包括
condition
: 此子模板的条件。您可以使用任何值或以下特殊条件之一。__odd
: 当前行是奇数行(仅对type="OddEven"
有效)。__even
: 当前行是偶数行(仅对type="OddEven"
有效)。__empty
: 测试的变量为空。__first
: 当前重复是第一个重复。__last
: 当前重复是最后一个重复。__single
: 模板不重复。__default
: 未匹配其他条件。
可选属性包括
<patTemplate:sub/>
标签不支持可选属性。
示例
<patTemplate:tmpl name="foo" type="OddEven"> <patTemplate:sub condition="__odd"> This is an odd row.<br/> </patTemplate:sub> <patTemplate:sub condition="__even"> This is an odd row.<br/> </patTemplate:sub> </patTemplate:tmpl>
"link" 标签
link
标签类似于 UNIX 系统上的符号链接,它仅引用不同模板的内容,而不创建其实际副本。
属性
必需的属性包括
src
: 引用的模板名称。
可选属性包括
<patTemplate:link/>
标签不支持可选属性。
<patTemplate:link/>
标签始终为空。
示例
<patTemplate:tmpl name="page"> <patTemplate:tmpl name="foo"> My name is {REALNAME}. </patTemplate:tmpl> <patTemplate:link src="foo"/> </patTemplate:tmpl>
"var" 标签
<patTemplate:var/>
标签可用于在模板中插入变量。它为通过花括号插入的普通变量添加了一些额外功能。
属性
必需的属性包括
name
: 变量的名称。
可选属性包括
copyFrom
: 应从哪个变量复制值的名称。default
: 如果变量未从 PHP 分配值,则为此变量设置的默认值。从 patTemplate 3.1.0a3 开始,这也可以是一个 PHP 函数。hidden
: 标志,表示变量是否在此模板位置隐藏(yes
)或显示(no
)。modifier
: 应应用 [wiki:Docs/Advanced/Modifiers 变量修饰符]。可以是 PHP 函数或修饰符类。从 patTemplate 3.1.0a3 开始,您可以通过逗号分隔的列表传递变量修饰符。modifiertype
: 修饰符类型。可能的值是auto
、php
和custom
。
示例
<patTemplate:tmpl name="foo"> This is a simple variable: <patTemplate:var name="simple"/>, it is identical to using {SIMPLE}. This is a variable with a default value: <patTemplate:var name="foo" default="bar"/>. This is a variable which is copied from another variable: <patTemplate:var name="bar" copyFrom="foo" modifier="ucfirst/>. This is a variable with a default value created by a PHP function: <patTemplate:var name="timestamp" default="time()"/>. </patTemplate:tmpl>
您还应查看描述 [wiki:Docs/Variables/DefaultValue 变量的默认值] 和 [wiki:Docs/Advanced/Modifiers 变量修饰符] 的部分。
"comment" 标签
<patTemplate:comment/>
标签可用于从输出中删除任何文本。它与 HTML 注释类似,但甚至不会输出。
属性
<patTemplate:comment/>
标签不支持任何属性。
示例
<patTemplate:tmpl name="foo"> This is sent to the browser. <patTemplate:comment> This is not sent to the browser. </patTemplate:comment> </patTemplate:tmpl>
创建新标签
patTemplate 允许您创建新的标签并实现 PHP 代码来处理它们。有关更多信息,请参阅[wiki:Docs/Developer/CustomFunctions 开发者文档]。
patTemplate 常见问题解答(FAQ)
我如何使用数据库查询的结果创建列表?
使用 patTemplate 创建列表非常简单,如果您同时使用 patTemplate 和 patDbc,则更加容易。让我们来看看列表模板。
<patTemplate:tmpl name="list"> <table border="1" cellpadding="10" cellspacing="0"> <tr> <th>Superhero Name</th> <th>Realname</th> <th>Action</th> </tr> <!-- template for list row --> <patTemplate:tmpl name="list_entry"> <tr> <td>{SUPERHERO}</td> <td>{REAL_NAME}</td> <td><a href="edit.php?id={ID}">edit</a></td> </tr> </patTemplate:tmpl> </table> </patTemplate:tmpl>
现在假设您有一个包含三个列(id、superhero 和 real_name)的 mysql 表,并且您希望在模板中显示该表的所有条目。
<?php $tmpl = new patTemplate(); $tmpl->setBasedir( "templates" ); $tmpl->readTemplatesFromFile( "superherolist.tmpl" ); $db = DB::connect('mysql://user:pass@localhost/myDb'); $query = "SELECT id, superhero, real_name FROM secretIdentities ORDER BY superhero"; $result = $db->getAll($query, DB_FETCHMODE_ASSOC); $tmpl->addRows( "list_entry", $result); $tmpl->displayParsedTemplate();
当然,您可以使用任何其他数据库抽象层或本机 PHP 函数进行数据库访问 - 在此示例中,我们使用了 [http://pear.php.net/package/DB PEAR::DB]。 $db->getAll(...)
仅执行 mysql_fetch_array() 并将所有行收集到一个返回的数组中。这个数组通过 addRows()
被传递给模板的 block list_entry
,patTemplate 会自动重复此块,以匹配数组中包含的行数。这使得处理数据库结果变得有趣。
我如何创建多行多列的表格?
在创建具有多个列的列表时,这通常是一个问题?我们将此问题称为“嵌套重复”,因为它不仅需要在创建二维表格时使用,还用于嵌套列表。乍一看,这可能相当困难,但一旦您理解了,它就相当简单……首先,让我们看看模板结构。
<table border="1" cellpadding="10" cellspacing="0"> <!-- template for table row --> <patTemplate:tmpl name="row"> <tr> <!-- template for table cell --> <patTemplate:tmpl name="cell"> <td>{REAL_NAME} is {SUPERHERO}</td> </patTemplate:tmpl> </tr> </patTemplate:tmpl> </table>
有两个模板,一个称为“row”,需要重复,另一个称为“cell”,在每一行中重复以显示内容。为了重复单元格和行,请使用以下 PHP 代码。
<?php // data to display $data = array( array( "real_name" => "Clark Kent", "superhero" => "Superman" ), array( "real_name" => "Bruce Wayne", "superhero" => "Batman" ), array( "real_name" => "Kyle Rayner", "superhero" => "Green Lantern" ), array( "real_name" => "Wally West", "superhero" => "The Flash" ), array( "real_name" => "Linda Danvers", "superhero" => "Supergirl" ), ); // number of columns per row $cols = 3; // calculate number of rows $rows = ceil(count($data)/$cols); $counter = 0; // loop for each row for ($i = 0; $i < $rows; $i++) { // clear cells from last row $tmpl->clearTemplate( "cell" ); // put data for one row in a new array $rowData = array(); for ($j = 0; $j < $cols; $j++) { if (isset($data[$counter])) array_push($rowData, $data[$counter++]); } // add the data of one row to the cells $tmpl->addRows( "cell", $rowData ); // parse this row and append the data to previously parsed rows $tmpl->parseTemplate( "row", "a" ); } $tmpl->displayParsedTemplate();
最重要的函数是 parseTemplate( "row", "a" )
,它解析模板并将其附加到之前解析的模板内容。这允许您解析多个行。
使用 array_chunk()
如果您已经安装了 PHP 4.2.0,则可以使用 array_chunk() 将完整数据拆分为每行一个数组。
我如何隐藏页面的一部分?
隐藏页面的一部分或在满足条件时显示它们非常简单。只需看看以下示例。
<patTemplate:tmpl name="page"> <html> <head> <title>patTemplate Example</title> </head> <body> <!-- This template is hidden by default --> <patTemplate:tmpl name="secret" visibility="hidden"> I know a secret: <b>Clark Kent is superman!</b> </patTemplate:tmpl> </body> </html> </patTemplate:tmpl>
此示例包含两个模板:page 和 secret,如果调用 displayParsedTemplate() 后加载这些模板,则不会显示。它不会显示,因为具有 visibility="hidden"
属性。如果您想显示页面模板,包括 secret 模板,可以使用 patTemplate 类的 PHP 方法 setAttribute。此方法接受三个参数,第一个是应设置属性的模板名称,第二个是属性名称,第三个是属性值。要更改模板的可见性,请使用以下 PHP 代码。
<?php $tmpl->readTemplatesFromFile( "myTemplate.tmpl" ); if( $knowSecret ** "yes" ) $tmpl->setAttribute( "secret", "visibility", "visible" ); $tmpl->displayParsedTemplate( "page" );
我如何使用数据库结果构建下拉菜单?
在构建网页时,需要创建下拉菜单,以便从数据库查询的结果中选择不同的选项。使用 patTemplate 创建它们非常简单。请看以下模板。
<patTemplate:tmpl name="page"> <html> <head> <title>patTemplate Example</title> </head> <body> <table border="0"> <tr> <td>Choose your superhero:</td> <td> <select size="1" name="superhero"> <option value="none">Please choose...</option> <patTemplate:tmpl name="dropdown_entry" type="condition" conditionvar="selected"> <patTemplate:sub condition="no"> <option value="{ID}">{SUPERHERO}</option> </patTemplate:sub> <patTemplate:sub condition="yes"> <option value="{ID}" selected="selected">{SUPERHERO}</option> </patTemplate:sub> </patTemplate:tmpl> </select> </td> </tr> </table> </body> </html> </patTemplate:tmpl>
如果你忽略HTML代码,模板相当简单。当然,每个文件都应该有一个完整的页面模板。这个模板还包含了实际的<select>
标签,它创建了一个HTML下拉菜单。此外,还有一个名为dropdown_entry的第二个模板。这个模板将用于动态构建下拉列表。模板类型设置为条件,因为每个条目可能有两种模式。要么它被默认选中,要么没有被选中。为了填充来自数据库查询的结果条目到下拉菜单,你需要以下代码
<?php $tmpl->readTemplatesFromFile( "myTemplate.tmpl" ); $defaultId = 19; $query = "SELECT id, superhero FROM heroes ORDER BY superhero"; $result = mysqli_query($link, $query); $entries = array(); while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) { // determine, whether entry should be selected by default if( $row["id"] ** $defaultId ) $row["selected"] = "yes"; else $row["selected"] = "no"; // add the entry to all other entries array_push( $entries, $row ); } // add all entries to the drop down menu $tmpl->addRows( "dropdown_entry", $entries ); // display the page $tmpl->displayParsedTemplate( "page" );
这将显示一个包含表格heroes中所有条目的下拉菜单,ID为19的超人将被默认选中。
切换到单选按钮组
如果你使用条件模板技术来打印选中和不选中的不同版本,你可以将下拉菜单切换到单选按钮组而不修改PHP代码。
我可以在不同的页面中重用模板吗?
当然可以。假设你有一个页脚和页眉,它们应该在你的所有页面中都相同,所以你只需要更改一次,它将在所有页面上更新。为此,首先创建两个文件,并将它们保存到你的模板目录中,分别命名为header.tmpl和footer.tmpl。模板可能看起来像这样
<patTemplate:tmpl name="header"> <h1>My Superhero database</h1> </patTemplate:tmpl>
以及这样
<patTemplate:tmpl name="footer"> <hr/> <span class="footer">Superhero database was last updated on 2001-12-24 (Oh, christmas).</span> </patTemplate:tmpl>
现在你可以通过使用<patTemplate:tmpl>
标签的src属性将这些两个文件包含在所有其他页面中
<patTemplate:tmpl name="page"> <html> <head> <title>Any page of the superhero database</title> </head> <body> <patTemplate:tmpl name="includedHeader" src="header.tmpl" parse="on"/> Here is the rest of the page... Can be anything from static HTML to other templates. <patTemplate:tmpl name="includedFooter" src="footer.tmpl" parse="on"/> </body> </html> </patTemplate:tmpl>
你可以像直接写入页面一样引用页眉和页脚模板,但只需要更改一次,所以这类似于模板的include()。
在文件夹中组织模板
当然,你还可以在子文件夹中组织模板。如果你想将共享模板放在模板文件夹的子文件夹中,只需使用<patTemplate:tmpl src="shared/header.tmpl" parse="off">
。如果您的basedir设置为templates
,patTemplate将加载模板./templates/shared/header.tmpl
。
扩展patTemplate
从3.0版本开始,patTemplate有一个更抽象的架构,这允许你添加或交换组件而不修改核心。要扩展patTemplate,你必须理解其内部结构和类树。
目录结构
patTemplate目录结构是根据PEAR概念构建的。主要的类patTemplate位于根目录(或如果你使用PEAR安装程序安装,则为/pat
)的patTemplate.php
文件中。这是你需要直接包含的唯一文件。你还会找到一个包含patTemplate所有模块的patTemplate
目录。在这个目录中有一个Module.php
文件,它包含了类patTemplate_Module
,作为所有不同类型模块(如函数、修饰符、读取器等)的基础类。此外,你还会找到可以用于patTemplate的每个模块的文件,如Reader.php
、Function.php
、TemplateCache.php
等。这些文件包含了你可以创建的模块的基础类。在patTemplate
文件夹中还有几个文件夹,帮助你组织实际的模块。读取器在patTemplate/Reader
中,函数在patTemplate/Functions
中等等。这意味着,如果你创建了一个应该用作模板中的FooMod
的新修饰符,你必须将其放在一个名为patTemplate/Modifier/FooMod.php
的文件中,否则patTemplate将无法找到它。
类树
patTemplate 是完全面向对象的代码。这意味着所有 patTemplate 模块都必须是类。大多数类都很简单,你只需要实现一个或两个方法。但无论如何,它们都必须是类,因为它们不能污染全局命名空间。文件和目录直接映射到类名。这意味着,patTemplate.php
包含一个名为 patTemplate
的类,而文件 patTemplate/Reader.php
包含名为 patTemplate_Reader
的类。如果你创建一个可以从数据库读取模板的读取器,你应该将其放置在 patTemplate/Reader/DB.php
中,并调用类 patTemplate_Reader_DB
。如果你不遵循这些简单的规则,patTemplate 目前将无法加载和实例化模块,并且你的应用程序将崩溃。
组件
patTemplate 由以下组件类型组成。
变量修饰符
变量修改器允许你在不编写任何 PHP 代码的情况下将 PHP 函数和方法应用到变量上。一旦你提供了修改器,模板设计者就可以轻松地在模板中使用它。变量修改器可以用来对变量应用 htmlspecialchars()
,以及创建图像和反转文本。
- [wiki:Docs/Developer/Modifiers 了解更多...]
模板读取器
默认情况下,patTemplate 从本地文件系统读取模板。但也许你更愿意将模板存储在数据库中或甚至共享内存中。通过创建一个新的模板读取器,这是可能的。读取器还允许你“融合”外部的模板系统。patTemplate 随带一个能够解释 [http://pear.php.net/package/HTML_Template_IT HTML_Template_IT](and PHPLib) 模板并将其视为正常的 patTemplate 文件的读取器。
- [wiki:Docs/Developer/Readers 了解更多...]
输出过滤器
输出过滤器允许你在将 HTML 代码发送到浏览器之前对其进行修改。可能的用例包括删除不必要的空白,甚至在客户端支持压缩内容的情况下压缩输出。
- [wiki:Docs/Developer/OutputFilters 了解更多...]
输入过滤器
输入过滤器在读取器分析模板之前应用。这允许你解压缩以 gzipped 格式存储的数据,或在模板中删除不需要的注释,从而提高读取器的性能。
- [wiki:Docs/Developer/InputFilters 了解更多...]
自定义标签/函数
自定义函数允许你为 patTemplate 命名空间创建新的标签。你必须编写一个类,该类将处理模板中出现的标签。这使你能够动态地将任何类型的动态生成的内容包含到模板中。
- [wiki:Docs/Developer/CustomFunctions 了解更多...]
模板缓存
模板缓存可以加快你使用 patTemplate 的网站的运行速度。它将以序列化格式存储读取器返回的结构,这种格式比原始模板读取得更快。patTemplate 随带一个缓存,它将缓存文件存储在文件系统中,但你可以在任何地方存储它们。
- [wiki:Docs/Developer/TemplateCaches 了解更多...]
模板转储器
转储可以帮助你调试模板,因为它以人类可读的格式呈现内部结构,包括所有模板、条件、修改器以及已设置的变量。初始版本具有 DHTML 转储功能,但你也可以创建显示纯文本、XUL 或你喜欢的任何内容的转储。
- [wiki:Docs/Developer/TemplateDumpers 了解更多...]
变量修饰符
变量修饰符赋予模板设计者强大的功能。假设您将一个非常长的文本传递给一个变量,但在布局中,设计者只有足够的空间显示简短的预告文本。使用修饰符,设计者可以应用“截断”修饰符来缩短您在PHP脚本中传递的文本。这只是变量修饰符的一个应用。
简介
应用修饰符非常简单。您只需使用 <patTemplate:var/>
标签,而不是只用花括号 { } 包围变量。然后您可以使用 'modifier' 属性来设置修饰符。
<patTemplate:tmpl name="page"> <div> <patTemplate:var name="myVar" modifier="nl2br"/> </div> </patTemplate:tmpl>
变量修饰符将在解析模板时应用于变量的值。有两种类型的修饰符
- 您可以使用任何PHP函数作为变量修饰符。修饰符必须只接受字符串作为参数,并返回字符串。nl2br() 或 htmlentities() 是变量修饰符的完美示例。
- 您可以创建自定义修饰符,它们提供扩展功能,并且可能受到 var 标签属性的 影响。
自定义修饰符
自定义修饰符是 patTemplate_Modifier 的子类,必须放在 patTemplate/Modifier 内。文件名必须与类名的最后一部分匹配。这意味着如果您想创建一个截断句子的过滤器,您必须创建一个名为 'patTemplate_Modifier_Truncate' 的新类,并将其放入 'patTemplate/Modifier/Truncate.php'。该类必须实现一个名为 modify( string value, array params ) 的方法,该方法必须返回修改后的值。您可以在该方法中执行任何修改值的操作。patTemplate 将传递两个参数给您的该方法
- string $value,变量的值
- array $params,一个关联数组,包含 var 标签的所有属性,但不包括那些内部使用的属性(name, default, copyFrom, modifier)
截断修饰符可能看起来像这样
<?php /** * patTemplate modfifier Truncate * * @package patTemplate * @subpackage Modifiers * @author Stephan Schmidt <schst@php.net> */ class patTemplate_Modifier_Truncate extends patTemplate_Modifier { /** * truncate the string * * @param string value * @param array value * @return string modified value */ public function modify( $value, $params = array() ) { /** * no length specified */ if( !isset( $params['length'] ) ) return $value; /** * is shorter than the length */ if( $params['length'] > strlen( $value ) ) return $value; return substr( $value, 0, $params['length'] ) . '...'; } }
如果您将此文件复制到修饰符文件夹,您可以通过在 <patTemplate:var/>
标签的修饰符属性中指定它,立即在模板文件中使用它。
<patTemplate:tmpl name="page"> <div> <patTemplate:var name="myVar" modifier="Truncate" length="50"/> </div> </patTemplate:tmpl>
如果您现在传递一个超过50个字符的值,修饰符将自动将其截断,然后再将其插入到模板中。
模板读取器
模板读取器用于从包含 <patTemplate:.../>
标签的任何字符串中创建内部模板结构。patTemplate 附带两个读取器,一个可以从文件读取,另一个可以直接从字符串读取。
从任何数据源读取
如果您想将模板存储在其他地方,可以简单地创建一个新的读取器。只需创建一个 patTemplate_Reader 的新子类,并将其放置在读取器目录中。您需要实现至少一个方法:readTemplates()。每当用户调用 patTemplate::readTemplatesFromInput() 时,patTemplate 将调用此方法,并传递要读取的模板的唯一标识符。这可以是文件名、URL 或数据库中主键的值。在读取模板后,您必须返回一个包含模板结构的数组。在大多数情况下,您可以使用 patTemplate_Reader::parseString(),它将应用正则表达式将模板源拆分成多个块,并解释所有标签。
<?php /** * patTemplate Reader that reads from a file * * @package patTemplate * @subpackage Readers * @author Stephan Schmidt <schst@php.net> */ class patTemplate_Reader_File extends patTemplate_Reader { /** * reader name * @var string */ protected $_name ='File'; /** * read templates from any input * * @final * @param string file to parse * @param array options, not implemented in current versions, but future versions will allow passing of options * @return array templates */ public function readTemplates($input, $options = array()) { $this->_currentInput = $input; $fullPath = $this->_resolveFullPath( $input ); $content = file_get_contents( $fullPath ); $templates = $this->parseString( $content ); return $templates; } /** * resolve path for a template * * @param string filename * @return string full path */ private function _resolveFullPath( $filename ) { $baseDir = $this->_options['root']; $fullPath = $baseDir . '/' . $filename; return $fullPath; } }
如果您想支持外部模板的 parse="off"
功能,您必须创建一个名为 loadTemplate()
的第二个方法。此方法将接收一个唯一标识符,并应返回与之关联的数据作为字符串。在上面的示例中,您只需剥离对 parseString()
的调用。
可能的读取器
- 从数据库读取
- 从模板服务器读取
- 从共享内存读取
其他模板引擎
读者还可以用于读取为其他模板引擎(如patTemplate之外)创建的模板。我们已交付了一个能够读取为HTML_Template_IT创建的模板并将它们视为patTemplate模板的读者。如果您想为其他引擎实现读者,您需要熟悉patTemplate的内部结构。我们将在此之后发布更多有关此主题的信息。
缓存
patTemplate支持返回的模板结构的缓存。由于缓存仍在测试状态,且内部插件API可能会更改,因此在此话题上的文档将在API足够稳定后发布。
输出过滤器
输出过滤器允许您在添加所有变量并解析模板后修改输出。您可以使用它来删除不必要的空白、压缩输出或混淆所有电子邮件地址。
创建您自己的输出过滤器
输出过滤器必须是一个从patTemplate_OutputFilter
扩展的类。您必须将包含您的过滤器的文件放置在patTemplate/OutputFilter
文件夹中。在这个类中,您只需要实现一个名为apply()
的方法。当脚本调用patTemplate::displayParsedTemplate()
时,patTemplate将调用此方法。在将生成的HTML代码发送到浏览器之前,您的过滤器将有机会修改或过滤生成的HTML。apply方法必须接受一个字符串参数,该参数将接收HTML代码。修改后,您只需返回修改后的HTML。
一个简单的示例
以下示例展示了如何实现一个输出过滤器,该过滤器在将HTML代码发送到浏览器之前从HTML代码中删除所有换行符、多余空格、缩进等。该类必须放置在文件patTemplate/OutputFilter/StripWhitespace.php中(实际上它已经包含在发行版中,因为这个示例包含在发行版中)。
<?php /** * patTemplate StripWhitespace output filter * * Will remove all whitespace and replace it with a single space. * * @package patTemplate * @subpackage Filters * @author Stephan Schmidt <schst@php.net> */ class patTemplate_OutputFilter_StripWhitespace extends patTemplate_OutputFilter { /** * filter name * * @abstract * @var string */ protected $_name = 'StripWhitespace'; /** * remove all whitespace from the output * * @param string data * @return string data without whitespace */ public function apply( $data ) { $data = str_replace( "\n", ' ', $data ); $data = preg_replace( '/\s\s+/', ' ', $data ); return $data; } }
应用输出过滤器
应用输出过滤器是一个简单的任务。您只需在您的patTemplate对象上调用一个方法并传递所需的输出过滤器。您可以通过应用尽可能多的输出过滤器来创建一个过滤器链。如果应用了多个过滤器,它们的调用顺序将与您应用它们的顺序相同。
<?php $tmpl = new patTemplate(); $tmpl->setRoot( 'templates' ); $tmpl->applyOutputFilter( 'StripWhitespace' ); $tmpl->readTemplatesFromInput( 'page.tmpl', 'File' ); /** * output filter will be applied here */ $tmpl->displayParsedTemplate();
向过滤器传递参数
您还可以创建一个可以被应用过滤器的脚本参数化的输出过滤器。如果过滤器类需要访问脚本设置的参数,您可以使用patTemplate_OutputFilter::getParam()
方法。在应用过滤器时,所有参数都必须作为数组传递给patTemplate::applyOutputFilter()
的第二个参数。
输入过滤器
输入过滤器与输出过滤器类似,但用途完全不同。它们允许您在模板从文件系统、数据库或任何其他位置读取后、在解析和分析模板之前对其进行过滤。
为什么需要输入过滤器?
您可以使用输入过滤器完成各种任务。您可以从模板中删除所有空白以加快解析过程、删除不必要的注释或将存储在压缩格式的模板解压。您还可以在某些特殊情况下使用它,在这些情况下,您需要修改模板,但无法在它们的原始存储位置中修改它们。
实现输入过滤器
实现输入过滤器与创建新的输出过滤器完全相同。您需要从一个新的类patTemplate_InputFilter
扩展并放置在patTemplate/InputFilter目录中的文件中。类的最后部分必须与文件名相同。在这个类中,您只需实现一个方法
string patTemplate_OutputFilter::apply( string templateCode )
patTemplate_Reader 会在解析器分析模板代码之前将模板代码传递给此方法,您可以按照需求对其进行修改。
一个简单的示例
以下示例在分析模板之前从模板中删除了HTML注释。这允许您在 <patTemplate:tmpl>
和 <patTemplate:sub>
标签之间放置它们,尽管不允许在那里放置数据。
<?php /** * patTemplate StripComments input filter * * Will remove all HTML comments. * * @package patTemplate * @subpackage Filters * @author Stephan Schmidt <schst@php.net> */ class patTemplate_InputFilter_StripComments extends patTemplate_InputFilter { /** * filter name * * @var string */ protected $_name = 'StripComments'; /** * compress the data * * @param string data * @return string data without whitespace */ public function apply($data) { $data = preg_replace('°<!--.*-->°msU', '', $data); return $data; } }
应用输入过滤器
应用输入过滤器是一个简单的任务。您只需在您的 patTemplate 对象上调用一个方法并传递所需的输出过滤器。您可以通过应用尽可能多的输入过滤器来创建一个过滤器链。如果您应用了多个过滤器,它们将以您应用它们的相同顺序被调用。
<?php $tmpl = new patTemplate(); $tmpl->setRoot('templates'); $tmpl->applyInputFilter('StripComments'); $tmpl->readTemplatesFromInput('page.tmpl', 'File'); /** * output filter will be applied here */ $tmpl->displayParsedTemplate();
向过滤器传递参数
您还可以创建一个可以被应用过滤器的脚本参数化的输入过滤器。如果过滤器类需要访问脚本设置的参数,您可以使用方法 patTemplate_InputFilter::getParam()
。在应用过滤器时,所有参数都必须作为数组传递给 patTemplate::applyInputFilter()
的第二个参数。
自定义标签
自定义函数允许您创建新的标签,并定义它们应该如何被处理。这样,您可以向模板设计师提供工具,他们可以使用这些工具插入任何动态内容。想象一下,在您的网站上,用户可以注册并使用用户名登录。您可以创建一个新的标签,从数据库中检索名称并在模板中显示它。其他示例包括 gettext 实现。
使用自定义函数
使用自定义函数就像吃奶酪蛋糕一样简单。它们可以像内置标签 tmpl、sub、var 等一样使用。
<patTemplate:tmpl name="page"> <div> Today is <patTemplate:time format="m/d/Y"/> </div> </patTemplate:tmpl>
这将输出 "今天是 [当前日期]。"
,其中 [当前日期] 将被替换为当前日期。
<patTemplate:tmpl name="root"> This is a template that is used to display code. <patTemplate:phpHighlight> <?php $i = 0; while( $i < 10 ) { echo "This is line $i.<br />"; $i++; }?> </patTemplate:phpHighlight> </patTemplate:tmpl>
在上面的示例中,在 <patTemplate:phpHighlight>
标签之间封装的 PHP 代码将在输出中语法高亮显示。
创建自定义函数
自定义函数必须放在 patTemplate/Function 中,并从 patTemplate_Function 扩展。您必须实现一个代表函数的方法:string patTemplate_Function::call( array params, string content ) 读取器将传递一个关联数组,包含您标签的所有属性,以及一个作为第二个参数的字符串,该字符串将包含在开闭标签之间的所有字符数据(以及 HTML 标签)。在此方法中,您可以计算结果并将其作为字符串返回。然后,将此结果插入模板中,代替您的函数标签以及封装的内容。您可以使用 patTemplate/Function 文件夹中定位的所有函数,因为 patTemplate 会自动加载类。模板函数将在分析模板时进行评估,目前无法在函数中使用模板变量或任何来自 PHP 脚本的数据。函数可以是嵌套的,patTemplate 将始终首先评估最内层的函数。
代码示例
此示例是自定义函数 time 的代码,该函数可以显示当前时间以及重新格式化传递给它的任何时间戳。
<?php /** * patTemplate function that calculates the current time * or any other time and returns it in the specified format. * * @package patTemplate * @subpackage Functions * @author Stephan Schmidt <schst@php.net> */ class patTemplate_Function_Time extends patTemplate_Function { /** * name of the function * @var string */ protected $_name = 'Time'; /** * call the function * * @param array parameters of the function (= attributes of the tag) * @param string content of the tag * @return string content to insert into the template */ public function call( $params, $content ) { if( !empty( $content ) ) { $params['time'] = $content; } if( isset( $params['time'] ) ) { $params['time'] = strtotime( $params['time'] ); } else { $params['time'] = time(); } return date( $params['format'], $params['time'] ); } }
模板缓存
模板缓存已经开发出来以加快基于 patTemplate 的应用程序的速度。它将节省分析模板文件的额外开销,对于每个请求。相反,它将序列化读取器的结果并将其存储在您喜欢的任何位置;在下一次请求相同模板时,它将检查文件是否仍然有效,并从缓存中加载它。
它是如何工作的?
当调用 patTemplate::readTemplatesFromInput()
时,patTemplate 会包含并实例化所需的读取器,然后加载和分析您指定的模板。这将在每次请求模板时执行,尽管这个过程不受任何变量或用户反馈的影响。这种技术有两个缺点
- 读取器类包含1400多行代码,需要编译
- 读取器使用了 preg_* 函数,这可能很耗时
为了消除这些性能瓶颈,我实现了模板缓存,它实现了一个相当简单的功能:在读取器分析模板并返回包含结构的数组后,模板缓存将序列化该结构并将其与一个唯一键存储起来。在下一次请求时,patTemplate 会询问模板缓存,是否存在特定键的存储结构。如果是的话,它将被反序列化并用于代替重新读取模板。
使用模板缓存
和所有 patTemplate 模块一样,使用模板缓存很简单。基本上,您只需要在脚本中添加一行代码。
<?php $tmpl = new patTemplate(); $tmpl->setRoot( 'templates' ); /** * Use a template cache based on file system */ $tmpl->useTemplateCache( 'File', array( 'cacheFolder' => './tmplCache', 'lifetime' => 60 ) ); $tmpl->readTemplatesFromInput( 'page.tmpl', 'File' ); $tmpl->displayParsedTemplate();
useTemplateCache() 调用的第一个参数定义了应该使用哪个缓存。如果您不确定安装了哪些缓存,请查看 patTemplate/TemplateCache 文件夹。第二个参数是一个包含模板缓存所有参数的数组。您需要查看您使用的模板缓存文档,以获取所有受支持参数的列表。
在使用 'File' 缓存的示例中,有两个参数
- cacheFolder 定义了缓存文件将存储的位置
- lifetime 定义了缓存的持续时长。在这种情况下,我们使用60秒的缓存。您也可以将缓存设置为 'auto',如果您想当源文件更改时重建缓存。
创建新的模板缓存
patTemplate 随附了一个模板缓存,该缓存在文件系统上存储数据。如果您需要一个更快的存储容器,如共享内存,您可以轻松实现。在 patTemplate/TemplateCache 中创建一个新文件,并创建一个扩展 patTemplate_Cache 的类。在这个类中,您只需要实现以下方法
array patTemplate_TemplateCache::load( string key, int modificationTime )
boolean patTemplate_TemplateCache::write( string key, array templates )
load() 方法将接收一个唯一键以及原始文件被修改的时间(如果读取器支持此功能)。您需要检查是否存在指定键的缓存文件以及它是否仍然有效。如果文件有效,您需要反序列化存储的数据并将结果模板结构返回给 patTemplate。write() 方法将接收唯一键以及要存储的模板结构。只需序列化它并使用键存储,以便稍后可以加载。
查看代码
要完全理解模板缓存的工作原理,请查看 'File' 缓存
<?php /** * patTemplate Template cache that stores data on filesystem * * Possible parameters for the cache are: * - cacheFolder : set the folder from which to load the cache * - lifetime : seconds for which the cache is valid, if set to auto, it will check * whether the cache is older than the original file (if the reader supports this) * * @package patTemplate * @subpackage Caches * @author Stephan Schmidt <schst@php.net> */ class patTemplate_TemplateCache_File extends patTemplate_TemplateCache { /** * parameters of the cache * * @var array */ protected $_params = array( 'cacheFolder' => './cache', 'lifetime' => 'auto' ); /** * load template from cache * * @param string cache key * @param integer modification time of original template * @return array|boolean either an array containing the templates or false cache could not be loaded */ public function load( $key, $modTime = -1 ) { $filename = $this->_getCachefileName( $key ); if( !file_exists( $filename ) || !is_readable( $filename ) ) return false; $generatedOn = filemtime( $filename ); $ttl = $this->getParam( 'lifetime' ); if( $ttl ** 'auto' ) { if( $modTime < 1 ) return false; if( $modTime > $generatedOn ) return false; return unserialize( file_get_contents( $filename ) ); } elseif( is_int( $ttl ) ) { if( $generatedOn + $ttl < time() ) return false; return unserialize( file_get_contents( $filename ) ); } return false; } /** * write template to cache * * @param string cache key * @param array templates to store * @return boolean true on success */ public function write( $key, $templates ) { $fp = @fopen( $this->_getCachefileName( $key ), 'w' ); if( !$fp ) return false; flock( $fp, LOCK_EX ); fputs( $fp, serialize( $templates ) ); flock( $fp, LOCK_UN ); return true; } /** * get the cache filename * * @param string cache key * @return string cache file name */ private function _getCachefileName( $key ) { return $this->getParam( 'cacheFolder' ) . '/' . $key . '.cache'; } }
如你所见,实现模板缓存非常简单,不应给经验丰富的 PHP 开发者带来问题
模板转储器
输出器可以帮助您调试应用程序,因为它们显示有关已加载模板和分配变量的信息。patTemplate 已经开发出来帮助解决 Web 问题,其输出通常在网页浏览器中显示。这就是为什么我们提供了一个显示 patTemplate 属性的优美(且交互式)HTML 版本的输出器。
编写新的输出器
如果您在 CLI 环境中使用 patTemplate 或不喜欢我们提供的 Dump 风格,您可以实现自己的 Dumper 对象。只需按照以下步骤操作
- 在 patTemplate/Dump 中创建一个新文件
- 在这个文件中创建一个新的类,该类扩展 patTemplate_Dump
- 实现所需的方法:
displayHeader()
、displayFooter()
、dumpGlobals()
和dumpTemplates()
displayHeader()
和 displayFooter()
方法不接受任何参数。dumpGlobals()
方法将接收一个包含所有全局模板变量的数组。dumpTemplates()
方法将接收两个数组,一个包含模板结构和内容,另一个包含已分配的变量。
使用 print_r()
函数。
为了熟悉传递给 Dump
对象的结构,我们建议使用 print_r()
或 var_dump()
在参数上。