wernerwa/pat-template

patTemplate 是一个功能强大的非编译模板引擎,它使用 XML 标签将文档分成不同的部分。

3.2.3 2023-07-12 23:07 UTC

This package is auto-updated.

Last update: 2024-09-13 01:53:44 UTC


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中有两种类型的变量:

  1. 局部变量,仅在添加变量的模板中可用
  2. 全局变量,在所有模板中可用

要在模板中放置变量,需要将变量用大括号括起来。变量只能由大写字母、数字、破折号和下划线组成

<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}

局部变量和全局变量方法之间有两个区别

  1. 全局方法 不需要 将模板名称作为第一个参数。
  2. 全局方法 不接受 数组作为变量的值。

如果变量名在全局和局部中都使用,则局部变量具有优先级。

进一步阅读

有关变量的更多信息,您可以阅读

设置变量的默认值

当使用 <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>

函数和方法将在从文件读取模板时进行评估。您无法从该函数访问变量的值。这正是应该使用 变量修饰符 的原因。

从其他模板访问变量

在以下两种情况下,您可能希望从任何其他模板访问变量

  1. 显示变量的值
  2. 将值用作条件模板的条件

在这两种情况下,您都可以使用 点语法 来解决问题。

从其他模板导入变量

要将不同模板中的一个变量导入当前模板,您必须使用具有 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/elseswitch/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() 函数应根据当前登录用户的状态返回 adminuser。因此,仅检查 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方法。它接受两个参数

  1. 选项的名称
  2. 选项的值

示例

$tmpl = new patTemplate();
$tmpl->setOption('allowFunctionsAsDefault', true);

可用的选项

以下表格显示了所有可用的选项

|| 选项 || 描述 || 可能的值 || || maintainBc || patTemplate是否应维持与2.x版本的向后兼容性。如果设置为true,您可以在<patTemplate:sub/>标签中使用emptydefault而不是!__empty!__default || truefalse || || defaultFunction || 应该调用的模板函数(即用户定义的标签)的名称 || 任何字符串 || || allowFunctionsAsDefault || 是否允许将PHP函数指定为变量的默认值。 || truefalse ||

高级功能

patTemplate不仅限于在HTML模板中替换占位符。

在这里,您可以找到有关更复杂功能的教程

  • [wiki:Docs/Advanced/Modifiers 变量修改器]
  • [wiki:Docs/Advanced/TemplateCache 使用模板缓存提高性能]
  • [wiki:Docs/Advanced/OutputFilters 输出过滤器]
  • [wiki:Docs/Advanced/InputFilters 输入过滤器]
  • [wiki:Docs/Advanced/External 包含外部模板]

从各种数据源读取模板

patTemplate不仅限于从文件系统读取模板,而是采用基于驱动的方法从几乎任何地方读取模板。

这种基于驱动的方法有两个优点

  1. 可以从任何数据源读取模板
  2. 不同的驱动程序可以解析不同的模板格式

读取模板的驱动程序称为模板读取器。目前,以下[源:trunk/patTemplate/Reader/读取器]是可用的

在调用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,模板的唯一ID
  • content,包含实际模板的文本字段

如果你想从数据库中读取名为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(),过滤器都将应用于此模板。

可用的过滤器

以下过滤器包含在发行版中

所有输出过滤器都位于[source:trunk/patTemplate/OutputFilter/ patTemplate/OutputFilter/]文件夹中。您还可以轻松[wiki:Docs/Developer/OutputFilters实现新的过滤器]。

使用输入过滤器

输入过滤器应用于模板文件的内容读取器分析标签之前。这使得您能够修改原始HTML代码并动态插入由模板引擎解释的patTemplate标签或变量。

使用输入过滤器非常简单,您只需要将过滤器的名称传递给applyInputFilter()方法。

$tmpl->applyInputFilter('StripComments');

StripComments输入过滤器将在patTemplate分析之前从文件中删除所有HTML和JavaScript注释。这有两个优点:

  1. 读取器更快,因为要解析的HTML代码更少。
  2. 您可以在<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:标志,指示是否应将系统变量添加到模板。可能的值是booleanintegeroff
  • 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 : 模板类型(standardconditionsimpleCondition)、OddEvenmodulo
  • unusedvars : 未分配值的变量将应用的默认行为。可能的值是 stripignorecommentnbsp
  • useglobals : 标志,表示是否应在条件中检查全局变量。仅当 type 设置为 conditionsimpleCondition 时使用。
  • varscope : 变量将从中导入的其它模板列表,以逗号分隔。
  • visibility : 模板的可见性。可能的值是 visiblehidden
  • whitespace : 将应用于模板的空白处理。可能的值是 keeptrim

示例

<patTemplate:tmpl name="foo">
  some content
</patTemplate:tmpl>

"sub" 标签

<patTemplate:sub/> 标签在 <patTemplate:tmpl/> 标签内使用,如果其 type 属性设置为 conditionOddEvenmodulo。它用于定义依赖于不同条件的内容。

属性

必需的属性包括

  • 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 : 修饰符类型。可能的值是 autophpcustom

示例

<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.phpFunction.phpTemplateCache.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 会包含并实例化所需的读取器,然后加载和分析您指定的模板。这将在每次请求模板时执行,尽管这个过程不受任何变量或用户反馈的影响。这种技术有两个缺点

  1. 读取器类包含1400多行代码,需要编译
  2. 读取器使用了 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 对象。只需按照以下步骤操作

  1. 在 patTemplate/Dump 中创建一个新文件
  2. 在这个文件中创建一个新的类,该类扩展 patTemplate_Dump
  3. 实现所需的方法:displayHeader()displayFooter()dumpGlobals()dumpTemplates()

displayHeader()displayFooter() 方法不接受任何参数。dumpGlobals() 方法将接收一个包含所有全局模板变量的数组。dumpTemplates() 方法将接收两个数组,一个包含模板结构和内容,另一个包含已分配的变量。

使用 print_r() 函数。

为了熟悉传递给 Dump 对象的结构,我们建议使用 print_r()var_dump() 在参数上。