neooblaster / template
基于Smarty语法的PHP模板引擎。
Requires
- php: >=5.6
This package is not auto-updated.
Last update: 2024-09-27 16:41:27 UTC
README
通过分离内容和形式,维护脚本变得轻而易举
状态
摘要
手册
英文:首先,这份手册是用法语编写的,以便简化并节省迁移文档的时间。
法语:首先,这份手册是用法语编写的,以便简化并节省迁移文档的时间
工作原理
根据希望实现的特定应用,使用模型可能就足够了。例如,如果您想给多个人发送电子邮件,只有与个人的相关信息会改变,其余部分是固定的。模型包含电子邮件和一些变量,我们可以为这些变量分配值。
在开发过程中,模型还可以将内容和形式分开。这样,开发语言和代码会更加清晰。这在处理复杂项目,如应用程序时尤其重要。
要组装内容和形式成一个最终的文档,需要一个执行所有必要操作的引擎。这个引擎由我基于PHPLIB提供的同名类的使用教程开发的Template类定义。
在本手册中,我们将逐步介绍Template类的不同概念和功能,以便逐步提升您的技能水平。
使用PHP Template类开始
正如之前宣布的那样,分离内容和形式的目的是为了维护程序,因此它们将更容易随着时间的推移进行维护。结合一个PHP类,通过简单的方法提供高级功能,开发大型应用程序变得非常容易。
鉴于我们将分离内容和形式,也就是说,将数据放在一边,而将显示结构放在另一边,我们将处理两个不同的文件。首先,我们将设计组成表单的HTML文件,然后我们将建立计算数据的脚本PHP,它将执行类以生成最终的文档。
上下文位置
在本手册中,我们将使用HTML文件进行操作,但完全可能组合其他类型的文件。重要的是,文档应像普通文本文件(非加密文件)一样可读。文件中的语法将决定其是否有效。以HTML为例,如果标签有效,则文档将完美运行。以下是一些您可能需要创建的文档示例。
随着解释的进行,我将构建一个类似的应用程序。它既不是动态的,也不是交互式的,但我会强调使用Template类解决问题的需求和方式。
- HTML页面
- CSS样式表
- JavaScript内容
- JSON数据结构
- XML数据结构
- INI数据结构
- 文本文档
在实施上下文的过程中,我们将一起建立工作环境,因为清晰地看到将要创建的文件路径非常重要,这也有助于突出我的工作方法。
因此,从一个文件夹开始,我首先将在其中创建一个名为Classes的文件夹,并将包含Template类以及其他现有类的PHP文件放入其中。然后,我将创建一个名为Templates的文件夹,其中将包含所有模型文件。在这个阶段,我们得到了以下文件夹结构。
┌ 03. Classe Template/
└─┬ Classes/
└ Templates/
安装Template类
在我们的例子中,我们从零开始。因此,在开始使用之前,我们必须获取并安装这个类。
在项目中的所有文件中,只有src文件夹中的文件是必需的。
系统由主文件Template.class.php组成。文件夹Help是引擎的内部手册。如果没有这些文件,使用help()方法将失败,并发出通知。
我们将把上面的所有文件复制到之前创建的Classes文件夹中。
到目前为止,类已安装并可使用。简而言之,这只涉及简单的复制粘贴。
创建HTML模型
在涉及脚本之前,我首先希望建立一个HTML模型,这将有助于介绍我的工作方法。我将文件放入预为此目的创建的Templates文件夹。我的第一个模型名为fichier_prisonnier.tpl.html。关于我的文件命名规范,我选择让它们包含指示文件角色的.tpl扩展名,以及允许软件使用适当的语法高亮的最终.html扩展名。完全可以创建一系列扩展名,例如.tpl-html,然后配置您的首选软件以识别这种扩展名。在我的方法中,这是标准的,因此不需要任何额外配置。
我们的第一个模型将是囚犯安全信息卡的实现样本。我们将直击核心,避免不必要的代码冗余。
文件 fiche_prisonnier.tpl.html
<h1>Fiche Prisonnier N° 31052016-1112</h1> <h3>Identité</h3> <ul> <li>Nom : TOUNET</li> <li>Prénom : George</li> <li>Age : 34 ans.</li> <li>Taille : 171 cm.</li> </ul> <h3>Délis et Crimes</h3> <h4>Crimes</h4> <ul> <li>Aucun</li> </ul> <h4>Délis</h4> <ul> <li>Aucun</li> </ul>
模型编写规则
[](待扩展) [](待扩展)
一个模型只是一个包含变量的简单文本文件。文件格式不重要。如果您想生成一个XML格式的文档,您可以创建一个XML格式的模型。重要的是要遵守文件内的语法。有一种专门的模型扩展名,即.tpl,它是template的缩写。
除了.tpl扩展名之外,我建议您接着添加文件的真实扩展名。这样,您的文本编辑器可以管理语法高亮显示。这样就可以更容易地处理模型。例如,对于最终将成为HTML页面的模型,我将命名我的模型为page.tpl.html。
使生成的文档有效,仅归因于其内容和遵守其语言语法。扩展名仅在Windows中才有用,以便将相应的软件与此类文件关联。习惯上,我们定义扩展名在输出文件中。所有这些都在文档渲染之前配置好,将在专门介绍配置引擎的章节中介绍。
尽管模型只是一个预先建立的框架,但有时需要内容能够适应。为此,存在一些指令,允许编写整洁且组织良好的代码。可以说,我们需要明智地使用工具。
变量
在我的模板引擎中,您可以选择表示变量的任何字符,只要它包含变量。更具体地说,用作符号的所选字符必须分别位于变量之前和之后,顺序与HTML或XML中的标签相反。变量常用的符号是百分号(%)。这种表示法,例如,用于定义Windows环境变量。以下是允许作为变量定界符的字符列表。
- 字母字符: [a-zA-Z]
- 数字字符 [0-9]
- 以下指定的特殊字符
- 百分号:
% - at 符号:
@ - 商业符号“&”:
& - 单引号:
' - 双引号:
" - 连字符:
- - 下划线:
_ - 点:
.
- 百分号:
- 对称字符: 用于自动完成标签结束
- 括号:
(和) - 方括号:
[和] - 大括号:
{和}
- 括号:
此列表也适用于变量名,尽管通常仅需要字母数字字符。
以下是不允许作为定界符和变量名的字符列表。如果使用它们,将导致编译错误。最坏的情况下,变量将不会被评估。
- 美元符号:
$ - 占位符:
* - 加号:
+ - 井号:
#
注意1:引擎对大小写敏感。这意味着它会区分变量%VARIABLE%和%variable%。
注意2:绝对不要在变量名中使用所选的定界符。
以下是一个有效变量的示例
Une première ligne comportant une %VARIABLE% valide.
Un seconde ligne avec une autre %variable% valide.
L'ensemble des %variables% du modèle doivent être délimitées avec le même symbôle.
Exemple de délimiteur accepté : %VAR%, @VAR@, $VAR$, _VAR_, -VAR-
Les {ACCOLADES}, les (PARENTHESES) et les [CROCHETS] sont pris en charge.
Ces exemple là sont aussi valables : {{VARIABLE}}, {[VARIABLE]} et {AZ_VARIABLES_ZA}
以下是一个无效变量的示例
Cette %VARIABLE est fausse, car ne dispose que d'un seul symbôle.Le tout est vu comme du simple texte.
Cette %VARIABLE@ est fausse, car ne respecte pas l'ordre inverse du délimiteur. Le tout est vu comme du simple texte.
Cette {VARIABLE{ est fausse, car ne respecte pas l'ordre inverse du délimiteur. Le tout est vu comme du simple texte.
Cette VARIABLE n'en est pas une, car ne dispose d'aucun délimiteur !
在命名变量时,我发现将它们写成大写字母很有趣。这样它们在文档中会显得更突出。这尤其有趣,因为具有语法着色功能的软件不会将它们视为变量。对于变量来说,我们真的不能再简单了!让我们看看它是如何适用于块的。
可重复块
首先,什么是可重复的块?块代表一组必须重复一定次数并且无限重复的行。例如,你想编写一个“姓名 - 名”的列表。如果我们知道“姓名 - 名”的确切数量,我们可以在模板中这样写:
<ul> <li>%NOM_1% - %PRENOM_1%</li> <li>%NOM_2% - %PRENOM_2%</li> </ul>
到目前为止,一切顺利。现在,如果我们需要为10个或更多的“姓名 - 名”编写,这可能会很快变得难以书写。此外,在传递数据时,这只会变得更加繁琐。这就是块的作用所在。
与变量类似,块不是由字符而是由标签界定。所有这些都组成了一条指令。
以下是块的开头和结尾标签。
<!-- BEGIN_BLOCK NOM_DU_BLOC --> <!-- END_BLOCK NOM_DU_BLOC -->
正如您所注意到的,指令由关键字BEGIN或END以及具有意义的_BLOCK组成。在这些指示符之后,找到块的名称。允许的字符与变量的名称相同,但严格禁止使用空格。请注意,块名称不是变量,因此没有界定。在文件行中,务必确保指令前后没有任何字符。如果是这样,则相邻的数据将不会重新传输。
如果我们重新考虑“姓名 - 名”的例子,我们得到:
<!-- BEGIN_BLOCK NOM_DU_BLOC --> <li>%NOM% - %PRENOM%</li> <!-- END_BLOCK NOM_DU_BLOC -->
注意,块内的变量始终由您定义的符号界定。请注意,指定的变量被封装在此块内。关于块的数据传输将在专用章节中解释。
嵌套块
有时,我们可能需要在块中重复一段代码,该块本身也将被重复。例如,你正在做用户资料,你不知道其数量。在这些资料中,你想列出用户曾从事的不同职业。职业的数量直接取决于用户。为了应对这种情况,我们只需插入一个新的块。这个块将位于一个块中。我们已经实现了块的嵌套。以下是一个可视化我的观点的例子。
<!-- BEGIN_BLOCK FICHE_UTILISATEUR -->
<div>
<h1>Fiche de %USR_PRENOM% %USR_NOM%</h1>
<ul>
<li>Age : %USR_AGE% ans.</li>
<li>Taile : %USR_TAILLE% cm.</li>
...
</ul>
<h2>Métier(s) exercé(s) : </h2>
<ul>
<!-- BEGIN_BLOCK USR_METIER -->
<li>%METIER%</li>
<!-- END_BLOCK USR_METIER -->
</ul>
</div>
<!-- END_BLOCK FICHE_UTILISATEUR -->
嵌套块的命名规则没有改变。重要的是,块必须有一个唯一的名称。绝对不能有两个具有相同名称的块。如果是这样,引擎将返回一个致命错误。关于嵌套块的传递信息将在专用章节中解释。
条件块
还存在另一种类型的块,即条件块。与可重复的块不同,当条件满足时,它将显示。它不会重复,但它可以很好地包含在普通块中。以下是如何声明一个条件块:
<!-- IF (%CONDITIONS%) AS NOM_TEST_CONDITIONNEL --> L'utilisateur fait partie du groupe "Admin", il à donc les droits d'accéder à ce contenu : (...) <!-- ENDIF NOM_TEST_CONDITIONNEL -->
条件块声明的标签处理变量,并在实际进行测试之前进行替换。
假设我将%CONDITIONS%替换为true,则块的内容将显示。同样,如果我用false替换,则内容将被忽略。
以下是您可以找到的一些条件测试示例:
Si ALLOWED = true; <!-- IF (%ALLOWED%) AS NOM_TEST_CONDITIONNEL --> alors le contenu est affiché <!-- IF (!%ALLOWED%) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré Si ALLOWED = false; <!-- IF (%ALLOWED%) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré <!-- IF (!%ALLOWED%) AS NOM_TEST_CONDITIONNEL --> alors le contenu est affiché Si LEVEL = 1 <!-- IF (%LEVEL% > 0) AS NOM_TEST_CONDITIONNEL --> alors le contenu est affiché <!-- IF (%LEVEL% < 0) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré Si LEVEL = -1 <!-- IF (%LEVEL% > 0) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré <!-- IF (%LEVEL% < 0) AS NOM_TEST_CONDITIONNEL --> alors le contenu est affiché Si ALLOWED = TRUE Si LEVEL = 1 <!-- IF (%ALLOWED% AND (%LEVEL% > 0)) AS NOM_TEST_CONDITIONNEL --> alors le contenu est affiché Si ALLOWED = TRUE Si LEVEL = -1 <!-- IF (%ALLOWED% AND (%LEVEL% > 0)) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré Si ALLOWED = FALSE Si LEVEL = 1 <!-- IF (%ALLOWED% AND (%LEVEL% > 0)) AS NOM_TEST_CONDITIONNEL --> alors le contenu est ignoré
就像真正的语言一样,如果您不满足条件,您可以定义备选情况。我指的是else if和else。
引擎还处理这种条件结构。以下是一个完整的示例,以向您展示应采用的语法:
<!-- IF (%AGE% < 18) AS CATEGORIE_AGE --> Catégorie : Mineur <!-- ELSEIF (%AGE% >= 18 AND %AGE% < 50) --> Catégorie : Adulte <!-- ELSEIF (%AGE% >= 50 AND %AGE% < 110) --> Catégorie : Senior <!-- ELSE --> Catégorie : Immortel <!-- ENDIF CATEGORIE_AGE -->
条件块和可重复块之间,以及条件块和可重复块之间,都可以进行嵌套。
请注意,您可以在条件字段中使用变量,并且必须使用变量。变量的评估取决于条件块的位置。
有了这个特性,我们开始偏离纯模型的概念,但这也避免了需要制作与可能性一样多的模型。
PHP代码块
尽管这与模型原则相悖,但在某些情况下,使用 PHP 是不可避免的。
要使用 PHP,而不是使用传统标签,我引入了一个专门的指令,如下所示:
<!-- BEGIN_PHP NOM_BLOC_PHP --> <!-- END_PHP NOM_BLOC_PHP -->
在这两个标签之间,PHP 语法保持不变。也就是说,不要忘记每个指令末尾的分号(``;``)。
更重要的是,您可以在所写的 PHP 代码中引入 Template 引擎的变量。首先将其转录为模型,然后再将其评估为 PHP 代码。
为了让模型中的 PHP 代码能与您的脚本通信,Template 类提供了一个伪全局变量 $_PHP。实际上,它允许在脚本和模型之间进行交互,但它不会像 $_SESSION 一样持续存在。它更多的是脚本和引擎之间的桥梁,但这也可能很有用。
为了简明扼要地说明这些观点,以下是一个使用示例:
<select> <!-- BEGIN_PHP DAY_NUMBER --> $_PHP['DAY_LANG'] = 'jour'; // Donnée passé du côté du script, mais ici pour la démo for($i = 1; $i < 32; $i++){ $ext = ($i == 1) ? 'er' : 'em'; echo "<option value="\"$i\"">$i$ext ".$_PHP['DAY_LANG']."</option>"; } <!-- END_PHP DAY_NUMBER --> </select>
我们得到以下内容:
<select> <option value="1">1er jour</option> <option value="2">2em jour</option> <option value="3">3em jour</option> <option value="4">4em jour</option> <option value="5">5em jour</option> <option value="6">6em jour</option> <option value="7">7em jour</option> <option value="8">8em jour</option> <option value="9">9em jour</option> <option value="10">10em jour</option> <option value="11">11em jour</option> <option value="12">12em jour</option> <option value="13">13em jour</option> <option value="14">14em jour</option> <option value="15">15em jour</option> <option value="16">16em jour</option> <option value="17">17em jour</option> <option value="18">18em jour</option> <option value="19">19em jour</option> <option value="20">20em jour</option> <option value="21">21em jour</option> <option value="22">22em jour</option> <option value="23">23em jour</option> <option value="24">24em jour</option> <option value="25">25em jour</option> <option value="26">26em jour</option> <option value="27">27em jour</option> <option value="28">28em jour</option> <option value="29">29em jour</option> <option value="30">30em jour</option> <option value="31">31em jour</option> </select>
对于历史记录,BEGIN_PHP 块是在 条件块 之前设计的。这本来可以用常规块和条件块来完成,但了解我们可以在模型中执行一些 PHP 是有益的。
块声明
在 Template 类的 3.0 版本中,我引入了两个新的指令。第一个指令允许在模型中声明一个用于将来使用的块。其好处是可以在多个地方使用相同的块,更重要的是,一个块可以嵌套自身,从而在模型中引入递归。第二个指令是用于“调用”已声明的块。
首先,我们总共介绍了三种类型的块:
- 可重复块
- 条件块
- PHP 块
根据要声明的块类型,指令会有一些变化。
具体来说,可重复块 和 PHP 块只需要一个唯一的标识符,而 条件块 需要一个额外的输入参数。
要声明一个只有标识符的块,声明指令如下:
DÉCLARATION D'UN BLOCK DE CODE REPETABLE : <!-- BEGIN_DECLARE (BLOCK) AS NOM_DU_BLOCK --> Le contenu entre les deux balises sera traité de la même manière qu'un bloc introduit par <!-- BEGIN_BLOCK --> Notez d'ailleurs que nous ne retrouvons pas les balises du bloc répétable puisque nous sommes en train de le déclarer ! <!-- END_DECLARE NOM_DU_BLOCK -->
对于 PHP 代码块,我们必须指示它是一个 PHP 块
DÉCLARATION D'UN BLOCK DE CODE PHP : <!-- BEGIN_DECLARE (PHP) AS NOM_DU_BLOCK_PHP --> Le contenu entre les deux balises sera traité de la même manière qu'un bloc PHP introduit par <!-- BEGIN_PHP --> Notez d'ailleurs que nous ne retrouvons pas les balises du bloc PHP puisque nous sommes en train de le déclarer ! <!-- END_DECLARE NOM_DU_BLOCK_PHP -->
要声明 条件块,除了标识符之外,还需要输入数据,声明方法如下:
DÉCLARATION D'UN BLOCK CONDITIONNEL <!-- BEGIN_DECLARE (IF->(%CONDITION%)) AS NOM_DU_BLOCK_CONDITIONNEL --> La balise d'ouverture du bloc conditionnel est assimilée par l'instruction de déclaration. Tout comme la balise de fermeture. Mais pour les cas alternatif "ELSEIF" et "ELSE", ces instructions doivent être écrite comme dans un <!-- IF (X) AS Y --> <!-- ELSE --> Si condition indiquée non remplie, alors c'est cette partie là qui sera affichée <!-- END_DECLARE NOM_DU_BLOCK_CONDITIONNEL -->
您可以在模型中的任何位置声明一个块。但请注意,它将被暂时存储,而不是在 <!-- BEGIN_DECLARE --> 指令所在的位置进行处理。
注意 1:在块中使用 BEGIN_DECLARE 指令将是透明的。
注意 2:一个由其自身指令使用的块也是暂时存储的,可以在任何地方调用。区别在于它将在您引入它的地方进行处理。
调用块
现在您已经知道了如何声明一个块,您需要了解如何在一个特定位置请求使用该块。调用指令如下:
UTILISER LE BLOC NOM_BLOCK CI-DESSOUS
<!-- USE (NOM_BLOCK) -->
必须在括号中指定一个已知块的名称。该块可以在 <!-- USE () --> 指令之后声明或引入,这不会造成问题,因为渲染程序在开始组合文档之前会暂时存储所有块。
我提醒大家,<!-- BEGIN_DECLARE --> 只是为了让程序知道这个块,它不会处理这个块。这样可以更好地组织模型和代码。如果您不想声明块,这并不麻烦,但在这个情况下,被调用的块必须以 <!-- BEGIN_BLOCK --> 的形式存在于模型中的某个地方。
最后,使用 USE 引入的块变量将根据其在文档中的位置(全局或块内)进行替换。
递归块
以 PHP 为例,一个函数如果是递归的,就是它会调用自己。最经典的情况是当一个函数的作用是清理一个目录。如果这个目录包含子目录,那么这个函数必须调用自己。
下面是一个递归函数的例子。
function remove_folder($folder_path){ /** Se positionner sur le dossier **/ $ouverture=@opendir($folder_path); /** Si l'ouverture à échouée, le dossier n'existe pas ou n'est pas un dossier **/ if (!$ouverture) return; /** Lire son contenu **/ while($fichier=readdir($ouverture)) { /** Si ce sont les références UNIX, on skip **/ if ($fichier == '.' || $fichier == '..') continue; /** Si c'est un dossier, on entre en recursion **/ if (is_dir($folder_path."/".$fichier)) { remove_folder($folder_path."/".$fichier); } /** Sinon c'est un fichier, on le supprimer **/ else { @unlink($folder_path."/".$fichier); } } /** Ferme le pointeur **/ closedir($ouverture); /** Enfin on supprime le dossier**/ @rmdir($folder_path); }
要创建一个 递归块,只需使用前面提到的 <!-- USE --> 指令。
<!-- BEGIN_BLOCK FOLDER --> <ul> <!-- USE (FOLDER) --> <!-- BEGIN_BLOCK FILES --> <li>%FILE%</li> <!-- END_BLOCK FILES --> </ul> <!-- END_BLOCK FOLDER -->
请注意,只有可重复的块才能进行递归。 事实上,尝试使用 条件块 或 PHP 进行递归会导致无限循环,因为触发调用的条件总是相同的。
模板包含
以下指令可以在页面的某个部分在整个网站上都是共同的部分时非常有用,比如页眉或页脚。这就是下面描述的模型包含指令。
INSTRUCTION D'INCLUSION DE MODELE
<!-- INCLUDE_TEMPLATE (%TEMPLATE_PATH_AND_FILE%) -->
可以在指令中使用变量。还可以将此指令包含在 普通块 或 条件块 中。
其特殊性在于指向模型的路径。实际上,指示的值 不是相对于包含指令的模板,而是 相对于执行 Template 类的脚本。
考虑以下目录和文件结构
┌ ./
├─┬ Template/
│ ├─┬ Common/
│ │ └─┬ header.tpl.html
│ │ └ footer.tpl.html
│ └── index.tpl.html
└── index.php
如果 index.php 使用模板 Templates/index.tpl.html,直观上你会指定这些值作为包含值,用于头部和页脚
<!-- INCLUDE_TEMPLATE (Common/header.tpl.html) --> <!-- INCLUDE_TEMPLATE (Common/footer.tpl.html) -->
在上面的情况下,编译将失败,因为 Template 类找不到指定的文件。需要指定从执行类的脚本开始的全路径,即从 index.php 开始。
<!-- INCLUDE_TEMPLATE (Templates/Common/header.tpl.html) --> <!-- INCLUDE_TEMPLATE (Templates/Common/footer.tpl.html) -->
[](4diese Les blocs dispo a partir de 3.2.0 anonymes)
从可重复块中访问简单变量
如块部分所述,块内部指定的变量 是隔离于该块的。
以“姓名 - 名”为例
<ul> <!-- BEGIN_BLOCK NOM_DU_BLOC --> <li> %NOM% - %PRENOM% </li> <!-- END_BLOCK NOM_DU_BLOC --> </ul>
如果我们有这些值要处理
结果将是以下这样
<ul> <li> DUPRE - Nicolas </li> <li> DUPRE - Julien </li> <li> DUPONT - Alain </li> </ul>
假设,我们想添加一个标题,而这个标题总是相同的
<ul> <!-- BEGIN_BLOCK NOM_DU_BLOC --> <li> %LABEL% : %NOM% - %PRENOM% </li> <!-- END_BLOCK NOM_DU_BLOC --> </ul>
我们将不得不有这个数据集
显然,值 Utilisateur 是重复的,在大量数据的情况下,会有数据冗余,这肯定会影响文档组成的效率。
为了避免这种情况,我实施了一个系统,允许块访问被认为是简单的变量。为此,只需简单地双重界定符即可。
<ul> <!-- BEGIN_BLOCK NOM_DU_BLOC --> <li> %%LABEL%% : %NOM% - %PRENOM% </li> <!-- END_BLOCK NOM_DU_BLOC --> </ul>
因此我们会得到以下结果
<ul> <li> Utilisateur : DUPRE - Nicolas </li> <li> Utilisateur : DUPRE - Julien </li> <li> Utilisateur : DUPONT - Alain </li> </ul>
我知道现在这听起来可能很抽象,但当你阅读了关于使用类和使用数据组装类的章节时,这会变得非常清楚!因此,我邀请你稍后再回过头来看这个点。
修改指令的合成代码。
可用性 >= v3.5.0。
使用Template类
使用引擎生成文档分为三个步骤。
第一个阶段是初始化引擎。
第二个阶段是配置它。
最后是文档生成阶段。
这种切割不是必需的,但为了提高代码可读性,建议这样做。
阶段1 - 初始化引擎
实际上,引擎只是一个包含简化其使用的方法的PHP对象。这正是PHP类的真正作用。首先要做的事情是使用require_once函数包含类。一旦类被加载,只需使用new关键字创建对象。
以下是一阶段的指令
注意:如果您使用autloader,则不需要require_once步骤。
/** CHARGEMENT DE LA CLASSE "Template" **/ require_once 'template.class.php'; /** INITIALISATION DU MOTEUR **/ $moteur = new Template();
在这个阶段,引擎还不能使用。我本来可以尝试将配置数据作为参数传递,但我认为编写起来会很繁琐,需要完全了解参数的顺序。使用配置方法很明智,因为这样代码更干净,更直观,因此更容易记忆,更重要的是,可以轻松地在任何时候修改某些参数。如果需要,您可以使用help()方法来显示所有可用的方法。
阶段2 - 配置引擎
根据您的需求,创建自定义文档需要哪些数据?以下是我们首先会提供的内容。
- 配置要使用的模型。
- 配置要在模型中使用的数据。
- 配置最终文档的名称。
实际上,这些都是引擎正常工作所必需的参数。然而,存在许多参数可以细化类的使用。
以下是使用引擎所期望的基本参数。
- 定义模型路径(.tpl文件或其他)
- 定义最终输出文件的名称(包括文件扩展名)
仅使用这两个参数,您就可以生成文档。相反,将不会处理任何数据,您将获得与模板完全相同的内容!但话虽如此,对于测试来说这已经足够了。
为了让Template类有用,需要将数据发送到引擎。这些参数可以被称为“伪可选”,因为类在没有它们的情况下也可以工作,但没有意义!以下是伪可选参数的列表
- 发送变量数据。
最后,还有许多完全可选的参数,对于类的正常运行不是必需的。说“非必需”并不意味着无用。以下是可选参数的列表
- 定义变量分隔符。默认的是
百分比(%),但如果你想使用其他的,你完全自由。 - 定义引擎的工作模式:生成文档,或者仅生成用于显示的文件。
- 在生成文档的情况下,定义文档存储的目录。
- 定义无论何种工作模式,处理时的临时工作目录。
- 在写入文档时定义处理
UTF8。在字符重音出现问题时。 - 在读取文档时定义处理
UTF8。在字符重音出现问题时。 - 如果通过邮件发送文档,定义邮件地址列表。
- 如果通过邮件发送文档,定义邮件对象。
- 如果通过邮件发送文档,定义邮件发送者地址。
- 如果通过邮件发送文档,定义邮件发送者名称。
以下详细说明了第二阶段,包括要使用的方法。我故意配置了所有参数,以便突出尽可能多的方法。
/** Configuration de base du moteur. **/ /** --- --- --- OBLGATOIRE --- --- --- **/ /** > Rappel, ces paramètres seul suffisent pour que le moteur fonctionne **/ /** - Indication du modèle à utiliser : **/ $moteur->set_template_file('Mes Modeles/fiche_utilisateur.tpl'); /** - Alternative à un fichier template : Une chaine de caractère (texte) **/ // $moteur->set_template_text('Je veux renderiser ce %TEXT% !'); /** - Indication du nom de sortie du fichier : **/ $moteur->set_ouput_name('ficher_utilisateur_2014.html'); /** Configuration "Pseudo-facultative" **/ /** --- --- --- PSEUDO-FACULATIF --- --- --- **/ /** > Rappel, ces paramètres sont pseudo-facultatif, car ils envoient les données qui remplacerons vos variables **/ /** > $variables est là pour schématiser. C'est votre programme qui générera son contenu **/> $variables = Array(); /** - Envois des données simples : **/ $moteur->set_vars($variables); /** Configuration des autres paramètres - Affinage de la config du moteur **/ /** --- --- --- --- --- --- --- --- FACUTLATIF --- --- --- --- --- --- --- --- **/ /** - Re-définition du délimiteur de variables : **/ $moteur->set_vars_delim('%'); // Ici on ré-applique le même délims /** Dans le cas d'un délimiteur de plusieurs caractères **/ /** Seul le symbôle d'ouverture est à définir. Le modèle fermant se compose de lui-même **/ /** Ce ne sont que des exemples **/ $moteur->set_vars_delim('{'); // Utilisation des crochets comme délimiteur >>> {VARIABLE} $moteur->set_vars_delim('('); // Utilisation des parenthèse comme délimiteur >>> (VARIABLE) $moteur->set_vars_delim('{('); // Utilisation Combinées >>> {(VARIABLE)} /** - Configuration du mode de rendu à "permanent" (production de document) **/ $moteur->set_render_type('permanent'); // Valeur possible : temporary, permanent /** - Définition du dossier de dépot de document final **/ $moteur->set_output_directories('Mes Documents', 'Archives'); // Au minimum un dossier doit être indiqué /** - Définition du dossier temporaire de travail **/ $moteur->set_temporary_repository('Temps'); /** - Forcer la concervation des fichiers temporaire pour analyser, etude ou debug **/ $moteur->set_keep_temp_file(true); // Par défaut vaut "false" /** - Définir le type de traiment de caractère lors de l'écriture du document **/ $moteur->set_utf8_write_treatment('none'); // Valeurs possible : none, encode, decode /** - Définir le type de traiment de caractère lors de la lecture du document **/ $moteur->set_utf8_read_treatment('none'); // Valeurs possible : none, encode, decode /** - Définition des destinataires lors de l'envois de mail **/ $moteur->set_mail_recipients('moi@hotmail.fr', 'toi@yahoo.com', 'eux@gmail.com'); /** - Définition de l'objet du mail lors de l'envois de mail **/ $moteur->set_mail_subject('Fichier utilisateur de 2014'); /** - Définition de l'adresse mail de l'émetteur si vous permettez le reply to **/ $moteur->set_mail_sender('rh@company.com'); /** - Définition du nom de l'emetteur afficher dans le client de messagerie **/ $moteur->set_mail_sender_name('ressource-humaine de company');
引擎已完全配置!现在只需执行引擎即可。
阶段3 - 执行引擎
最后一阶段非常简单。它只是使用一种方法来生成文档。PHP生成文档的指令是完全透明的。这意味着没有任何显示的消息。如果发生错误,脚本会停止并显示失败原因。要显示生成的文档,有一个适当的方法。它的作用是读取和显示生成的文档。要发送生成的文档通过邮件,只需使用为此目的准备的方法。还有一个第三个方法,它的作用是将以字符串形式恢复内容。这允许您对已生成的数据进行修改。
以下是完整使用时的第3阶段:生成、显示和发送邮件
/** EXECUTION DU MOTEUR **/ /** 1. Génération du document **/ $moteur->render(); /** 2. Afficher le document **/ $moteur->display(); /** 3. Envoyer un mail **/ $moteur->sendMail(); /** 4. Récupérer le contenu pour le stocker en BDD **/ $to_bdd = $moteur->get_render_content();
render() 和 display() 方法返回自身类,这允许以这种方式链接这些方法
/** EXECUTION DU MOTEUR **/ /** Génère le document et affiche le **/ $moteur->render()->display();
最后一阶段是最简单的。只需要做输出。最终,最复杂的不在于使用类,而在于编译要传递给引擎的变量。这就是为什么下一章将介绍如何组织信息。此外,还有一些方法,但附录位于文档末尾,用于解释每个方法的作用。
整理数据以发送到引擎
在上一章中,我解释了如何配置引擎。在第2阶段,我解释了如何将数据传递给引擎。然而,这并没有解释信息是如何组织的。
根据模型的大小和要传递的数据量,您很快就会遇到庞大的结构。这些数据结构通常由您的程序生成,该程序在传递之前进行检索和计算。然后它会组织这些数据,以便传递给引擎。这种复杂性需要详细的演示才能掌握基础知识。
编译和将数据传输到名为“简单”或“全局”的变量
定义模型var_simple.tpl
第一步是编写模型以查看数据以及我们需要的变量名。
以下是准备好的模型
<h1>Fiche Prisonnier N° %PRI_ID%</h1> <ul> <li>Prénom : %PRI_PRENOM%.</li> <li>Nom : %PRI_NOM%.</li> <li>Age : %PRI_AGE% ans.</li> <li>Taille : %PRI_TAILLE% cm.</li> </ul>
计算和执行脚本
第二步,是你的工作:计算并生成要发送的数据。在演示中,我手动定义信息。这里重要的是数据的组织以进行传输。
/** Configuration du moteur **/ $moteur->set_template_file('Templates/var_simple.tpl'); $moteur->set_output_name('Render/var_simple.html'); /** Assemblage des données **/ $prisonnier = array( 'PRI_ID' => '123456789', 'PRI_NOM' => 'Time', 'PRI_PRENOM' => 'Vincent', 'PRI_AGE' => '33', 'PRI_TAILLE' => '172', ); $moteur->set_vars($prisonnier); $moteur->render()->display();
渲染结果
以下是使用 render() 和 display() 方法获得的结果 [查看代码];
<h1>Fiche Prisonnier N° 123456789</h1> <ul> <li>Prénom : Vincent.</li> <li>Nom : Time.</li> <li>Age : 33 ans.</li> <li>Taille : 172 cm.</li> </ul>
如您所注意到的,传递信息需要使用关联数组。我们将“变量名”与“值”相关联。
编译和将数据传输到可重复块
在我们的先前的例子中,我们创建了一个囚犯档案。现在想法是列出其罪行。所犯的罪行不是预先定义的。因此,我必须使用一个块。以下是模型
定义模型var_bloc.tpl
以下是准备好的模型
<h1>Fiche Prisonnier N° %PRI_ID%</h1> <ul> <li>Prénom : %PRI_PRENOM%.</li> <li>Nom : %PRI_NOM%.</li> <li>Age : %PRI_AGE% ans.</li> <li>Taille : %PRI_TAILLE% cm.</li> </ul> <h2>Crimes :</h2> <ul> <!-- BEGIN_BLOCK CRIMES --> <li>Le %CRIME_DATE% : %CRIME_NAME% -> %CRIME_AMENDE% € - %CRIME_PEINE%</li> <!-- END_BLOCK CRIMES --> </ul>
计算和执行脚本
这次,键代表块,与该键相关联的是一个数组。
$moteur->set_template_file('Templates/var_bloc.tpl'); $moteur->set_output_name('var_bloc.html'); /** Données à envoyer au moteur **/ $prisonnier = array( // @Données Globales 'PRI_ID' => '123456789', 'PRI_NOM' => 'Time', 'PRI_PRENOM' => 'Vincent', 'PRI_AGE' => '33', 'PRI_TAILLE' => '172', // @Données Cloisonnées // CRIMES = Nom du block concerné 'CRIMES' => array( // Ce tableau compose le premier tour du bloc array( // Couple "Variable -> valeur" pour le premier tour uniquement 'CRIME_DATE' => '01.11.2014', 'CRIME_NAME' => 'Vol à main armée', 'CRIME_AMENDE' => '30000', 'CRIME_PEINE' => '3 ans' ), // Ce tableau compose le second tour du bloc array( // Couple "Variable -> valeur" pour le second tour uniquement 'CRIME_DATE' => '01.11.2013', 'CRIME_NAME' => 'Vol à l\'étalage', 'CRIME_AMENDE' => '500', 'CRIME_PEINE' => '6 mois avec sursis' ) ) ); /** Envois des données au moteur **/ $moteur->set_vars($prisonnier); $moteur->render()->display();
渲染结果
以下是使用 render() 和 display() 方法获得的结果 [查看代码];
<h1>Fiche Prisonnier N° 123456789</h1> <ul> <li>Prénom : Vincent.</li> <li>Nom : Time.</li> <li>Age : 33 ans.</li> <li>Taille : 172 cm.</li> </ul> <h2>Crimes :</h2> <ul> <li>Le 01.11.2014 : Vol à main armée -> 30000 € - 3 ans</li> <li>Le 01.11.2013 : Vol à l'étalage -> 500 € - 6 mois avec sursis</li> </ul>
对于块的数据组织与变量类似。对于块,我们将块名(键)与包含新数组的数组相关联,其中包含“变量名”-“值”的关联。因此,块将根据关联的数组数据生成。
编译和传输嵌套可重复块的数据
定义模型var_bloc_i.tpl
最后演示的目标是展示在块嵌套时数据的组织。如果您理解了嵌套机制,那么无论嵌套多少次,您都会理解!请注意,在嵌套方面,超过两层嵌套的情况相当罕见。
这种机制也适用于递归块。
我们的嵌套目的是列出共犯及其所犯的罪行。
以下是准备好的模型
<h1>Fiche Prisonnier N° %PRI_ID%</h1> <ul> <li>Prénom : %PRI_PRENOM%.</li> <li>Nom : %PRI_NOM%.</li> <li>Age : %PRI_AGE% ans.</li> <li>Taille : %PRI_TAILLE% cm.</li> </ul> <h2>Crimes :</h2> <ul> <!-- BEGIN_BLOCK CRIMES --> <li>Le %CRIME_DATE% : %CRIME_NAME% -> %CRIME_AMENDE% € - %CRIME_PEINE% - Complice : </li> <ul> <!-- BEGIN_BLOCK COMPLICES --> <li>%COMPLICE_ID% : %COMPLICE_PRENOM% %COMPLICE_NOM%</li> <!-- END_BLOCK COMPLICES --> </ul> <!-- END_BLOCK CRIMES --> </ul>
计算和执行脚本
在嵌套的情况下,嵌套块的数據应在父块的数据中定义。
$moteur->set_template_file('Templates/var_bloc_i.tpl'); $moteur->set_output_name('var_bloc_i.html'); $prisonnier = array( // @Global 'PRI_ID' => '123456789', 'PRI_NOM' => 'Time', 'PRI_PRENOM' => 'Vincent', 'PRI_AGE' => '33', 'PRI_TAILLE' => '172', // @Closure // CRIMES = Nom du bloc concernée 'CRIMES' => array( array( // @Global in @Closure 'CRIME_DATE' => '01.11.2014', 'CRIME_NAME' => 'Vol à main armée', 'CRIME_AMENDE' => '30000', 'CRIME_PEINE' => '3 ans', // @Closure in @Closure // COMPLICE = Nom du bloc imbriqué dans CRIMES 'COMPLICES' => array( // Donnée du complice numéro 1 array( // @Global in @Closure where is in @closure 'COMPLICE_ID' => '234567891', 'COMPLICE_NOM' => 'Du Jardin', 'COMPLICE_PRENOM' => 'Jean' ), // Donnée du complice numéro 2 array( // @Global in @Closure where is in @closure 'COMPLICE_ID' => '3456789121', 'COMPLICE_NOM' => 'Reno', 'COMPLICE_PRENOM' => 'Jean' ), // Donnée du complice numéro 3 array( // @Global in @Closure where is in @closure 'COMPLICE_ID' => '456789123', 'COMPLICE_NOM' => 'Les Noix', 'COMPLICE_PRENOM' => 'Jean-Jacques' ) ) ), array( 'CRIME_DATE' => '01.11.2013', 'CRIME_NAME' => 'Vol à l\'étalage', 'CRIME_AMENDE' => '500', 'CRIME_PEINE' => '6 mois avec sursis', 'COMPLICES' => array() ) ) ); $moteur->set_vars($prisonnier); $moteur->render()->display();
渲染结果
以下是使用 render() 和 display() 方法获得的结果 [查看代码];
<h1>Fiche Prisonnier N° 123456789</h1> <ul> <li>Prénom : Vincent.</li> <li>Nom : Time.</li> <li>Age : 33 ans.</li> <li>Taille : 172 cm.</li> </ul> <h2>Crimes :</h2> <ul> <li>Le 01.11.2014 : Vol à main armée -> 30000 € - 3 ans - Complice : </li> <ul> <li>234567891 : Jean Du Jardin</li> <li>3456789121 : Jean Reno</li> <li>456789123 : Jean-Jacques Les Noix</li> </ul> <li>Le 01.11.2013 : Vol à l'étalage -> 500 € - 6 mois avec sursis - Complice : </li> <ul> <li>04081111215 : Pierre Les Pruniers</li> </ul> </ul>
内置UTF-8处理方法
在解释如何配置引擎的章节中,我提到了两种我没有详细说明的方法,分别是 set_utf8_write_treatment() 和 set_utf8_read_treatment()。
在本章中,我将详细介绍这两个方法的作用。
为了引入这个话题,下面是一个最明确的例子。
使用 Template 类渲染 utf8_explain.tpl 文件。
Cublia pérès primiés risius lorem lacinia hâc habitasse cubliâ hâc vulputate pésuéré donéc,
sollicitudin platéa semper nostré égét m'conubié nisï massa quém integer massa tincidunt ipsum,
ût nostré primis aliquét ut eu ipsum pellentesque tristiqué class nostra。
Tristique aliquam primis egéstat vivamùs lilitoxic erat purus posuere vestibulum tincidunt eros phaséll�s facîlisis prétium,
condimentûm augueé porttitor alèquam platéa £at portitorsé aenean non pérès quis ut aliquàm,
curae dictumst vehicula tempus eu c'est-a-dire erat nequé péer libéro mié vestibulum. Aliquam nullä dui c�eur iaculis augueé c'est-a-dire curàé sagittis blandit imperdiet phasellus éuismod,
éuismod ïn éu leo lobortïs alèquam vélit pharetra £at augue bibéndum dès integer,
vivamùs odio ïn sodalés litoré suscipit ïn quisque turpis aenean arcu ipsum,
curàé ïpsum proin。
Pulviar nunc posuere ullamcorper nibh sociosqu senectus tellus aliquet sém curabitur,scéléréo laçus 19 169� quisque primiés sit turpis cubilia phaséll�s,
ïpsum himenaeos lobortis non varius erat suspendisse égét primis énis tincidûnt,
torétoré potenti nisi id dapibus incéptos mi prétium。
哦,我的天哪,发生了什么事?我的文本中为什么有这些方块?
实际上,这个文件是以 ISO-8859-1 编码保存的,而这个页面显示的是 UTF-8 内容。因此,字符编码不一致。页面因此无法显示字符。如果我们生成文档并显示它,我们会在编码层面上得到相同的结果。
当涉及单个非动态文件时,我们可以非常简单地手动更改编码。假设文件由第三方程序生成并写入 AINSI 或 ISO,你就不能再手动操作了。如果需要处理大量文件,这一点尤为重要。
为了解决这个问题,你可以在程序中进行转换,或者简单地使用提供的方法!
以下是如何使用这些方法正确显示最终文档内容的一种方式
$moteur->set_template_file('utf8_explain.tpl'); $moteur->set_output_name('Render/utf8_explain.html'); /** Force le décodage des caractères UTF-8 dans le document finalisé **/ /** Le fichier passe de l'encodage ANSI à ANSI as UTF-8 **/ /** De cette manière l'UTF-8 est déjà décoder et on peut l'afficher simple **/ $moteur->set_utf8_write_treatment('decode'); // Valeurs admise : none, encode, decode $moteur->render()->display();
render() 和 display() 方法的输出结果。
Cublia pérès primiés risius lorem lacinia hâc habitasse cubliâ hâc vulputate pésuéré donéc,
sollicitudin platéa semper nostré égét m'conubié nisï massa quém integer massa tincidunt ipsum,
ût nostré primis aliquét ut eu ipsum pellentesque tristiqué class nostra。
Tristique aliquam primis egéstat vivamùs lilitoxic erat purus posuere vestibulum tincidunt eros phaséll�s facîlisis prétium,
condimentûm augueé porttitor alèquam platéa £at portitorsé aenean non pérès quis ut aliquàm,
curae dictumst vehicula tempus eu c'est-a-dire erat nequé péer libéro mié vestibulum. Aliquam nullä dui c�eur iaculis augueé c'est-a-dire curàé sagittis blandit imperdiet phasellus éuismod,
éuismod ïn éu leo lobortïs alèquam vélit pharetra £at augue bibéndum dès integer,
vivamùs odio ïn sodalés litoré suscipit ïn quisque turpis aenean arcu ipsum,
curàé ïpsum proin。
Pulviar nunc posuere ullamcorper nibh sociosqu senectus tellus aliquet sém curabitur,scéléréo laçus 19 169� quisque primiés sit turpis cubilia phaséll�s,
ïpsum himenaeos lobortis non varius erat suspendisse égét primis énis tincidûnt,
torétoré potenti nisi id dapibus incéptos mi prétium。
没有进行任何操作,我们已经解决了字符编码问题。在我们的例子中,需要在最终文档中对字符进行“预解码”,但根据情况,可能需要在写入时进行编码。可能写入是正确的,但需要显示内容的系统使用的是ISO编码。在这种情况下,应该使用set_utf8_read_treatment()方法。在混合多种语言、文件和显示系统时,编码问题相当复杂。需要在这两种方法之间进行协调,以获得期望的结果。无论如何,请注意,set_utf8_write_treatment()和set_utf8_read_treatment()都接受相同的值。
none编码解码.
请自己在这两种方法之间切换,直到找到期望的结果。
数据维护
如果您想在同一脚本中多次使用Template类的实例,只需对数据进行一些更改而不必完全重新定义,类提供了三种数据维护方法。
更新数据
版本 >= v3.3.0。
第一种方法update_vars()允许快速更新一组数据。它接受一个参数,即一个数组(array),其结构类似于在“准备数据发送到引擎”章节中所述。
该方法遍历数组。如果数据已经存在,则更新该数据。如果数据不存在,则添加该数据。
# Créer un premier rendu avec un jeu de donnée initial $moteur->set_vars([ 'NOM' => 'DUPRE', 'PRENOM' => 'Nicolas' ]); $moteur->render()->display(); # Créer un second rendu $moteur->update_vars([ 'PRENOM' => 'Julien', 'AGE' => 29 ]); # Jeu de donnée effectif : # NOM = DUPRE # PRENOM = Julien # AGE = 29 $moteur->render()->display();
切换布尔值
为了简化布尔变量状态的变化,而不是使用需要使用关联数组的update_vars()方法,我创建了一个名为xor_vars()的方法,其目的是切换指定的变量的值。
具体来说,如果值是true,则将其切换到false,反之亦然。
该方法非常灵活,可以接受所需的所有值。这些值必须是string或array类型。
如果您发送一个数组,该数组必须是一个包含string类型值的列表。
以下是一个用于说明状态变化的示例。
$moteur->set_vars([ 'SIGNED' => true 'ADMIN' => false ]); $moteur->xor_vars('SIGNED'); # La valeur SIGNED vaut maintenant FALSE
以下是一个使用示例。
# Nom de clé purement imaginaire $moteur->xor_vars( 'SIGNED', 'ADMIN', [ 'ARTICLE_1_READ', 'ARTICLE_2_READ', 'ARTICLE_2_READ' ], 'GRANTED' );
重要:如果键不存在于发送到引擎的变量注册表中,则不会发出任何通知,但会在Template类的实例的错误历史记录中记录一个条目。
删除数据
最后,如果您想通过删除未使用的变量或其他原因来优化数据,可以使用unset_vars()方法将它们从注册表中删除。
在参数方面,它与xor_vars方法具有相同的功能。它接受所需的所有参数,类型为string或array。
如果您发送一个数组,该数组必须是一个包含string类型值的列表。
$moteur->set_vars([ 'SIGNED' => true 'ADMIN' => false ]); $moteur->unset_vars('ADMIN'); # Le registre ne contient plus que la variable SIGNED
Template类的内置手册
如本手册开头所述,如果您在安装中添加了help文件夹,Template类将能够以类似于PHP手册的方式显示其手册。
要生成手册,只需实例化引擎并调用help()方法。
$moteur->help();
此方法生成输出(HTML代码),因此在此阶段,已经发出了headers HTTP。但是,它没有定义content-type。此外,如果脚本没有中断,手册将插入到执行调用的地方。
如果您需要更详细的手册,并且拥有phpDocumentor工具,您可以自动生成文档。为此,您需要下载整个项目,然后在项目根目录下输入phpdoc命令。
附录
在前面的章节中,我一定提到了一些在配置引擎中非必要的某些方法。还有一些方法甚至不是为了配置而存在的。它们的作用是帮助您进行开发。在本附录中,我将向您介绍最重要的方法,这些方法与现有引擎并行,因此了解它们非常有用!
debugPath方法
"debugPath" 方法显示了执行 "Template" 类的目录的分层视图。如果我们重新讨论模型包含的例子,这个方法有助于识别到达模型的路径。在基础层面上,这个方法在自身开发中更有用,但也可以帮助任何开发。
/** Invocation de la méthode "debugPath" **/ $moteur->debugPath();
下面是一个返回结果的示例。由于本文档的工作方式,这里的结果并不十分清晰。我们只能看到索引和创建的临时目录。
Below, the neighborhood of the current folder where the class is executed :
Array
(
[0] => .
[1] => ..
[2] => Template_V_3_5_0.id
[3] => index.php
)
get_render_content方法
在前面的一些章节中,"get_render_content" 方法被简要提及。这个方法只能在 "render" 方法之后调用。与直接显示结果的 "display" 方法不同,它获取相同的内容并返回。这样,您可以使用变量进行修改,从而对生成的文档进行修改。
假设您有一个用于生成配置 JSON 字符串的 "template" 文件,并且您想以 event-stream 格式通过 SSE 发送它。目前,由于针对引擎的特定指令,您的模型包含换行符。换行符与 event-stream 不兼容。因此,您将首先使用模型生成配置 JSON,这比在 PHP 脚本中间构建它更方便,然后以这种方式删除您的换行符。
下面是一个示例,以部分说明这种情况
/** Génération de la configuration JSON **/ /** (....) **/ /** Récupération du contenu calculé **/ $sse_output = $moteur->get_render_content(); /** Suppression des EOL de la chaine **/ $sse_output = str_replace("\t", "", $sse_output); $sse_output = str_replace("\n", "", $sse_output); $sse_output = str_replace("\r", "", $sse_output); /** Envois des entêtes **/ header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); /** Envois du contenu **/ echo "data: $sse_output\n\n"; echo "retry: ".SSE_RETRY."\n";
set_keep_temp_file方法
"set_keep_temp_file" 方法用于 "保留临时文件",正如其名所示,它允许您不删除包含在生成文档时创建的文件的类的工作环境。这主要是在实际开发类时有用,但在生成文档出现问题时,这个方法可能有助于您确定问题的根源。
无论您是否定义了临时文件存储目录,引擎都会生成文件。区别在于,如果没有定义目录,它的工作环境将在执行类的同一目录中创建。
此配置指令不需要在执行 "render" 生成方法之前执行
/** Demande de conservation des fichiers temporaires **/ $moteur->set_keep_temp_file(true);
通常,当脚本结束时,工作环境会自动删除,除非使用此方法进行其他指示。然而,如果在执行类时发生错误,工作目录可能不会被删除。在这种情况下,您可以使用以下方法强制删除目录。
set_render_type方法
根据需要,生成的文档不一定需要保留。如果您想设计一个希望将内容和形式分开的应用程序,您不能保留文件,因为内容仍然会根据用户和可用的数据动态变化。这种模式被认为是文档临时生成。这是默认行为。
然而,它也可以作为文档组合程序使用,就像在发票组合中可能需要的那样,这种文档需要保留和归档。我将此模式称为 "永久" 模式。
进入 "永久" 模式并不会阻止使用所有现有方法,但是文档将同时被放入您指定的存储目录中。因此,定义存储目录成为必需的。
下面是一个使用定义文档存储目录的方法的示例。
/** Passer le moteur en tant que générateur de document **/ $moteur->set_render_type('permanent'); // Accepte permanent & temporary /** Définition du ou des dossiers de dépot (destination) **/ /** Si le script executant la classe se trouve dans le dossier "Appli" **/ /** Les dossiers indiqués doivent se trouver eux-même dans "Appli" **/ $moteur->set_output_directories('Services/Compta', 'Archives/Services/Compta');
PHP Template 类不仅可以在Web应用程序中使用。如果PHP脚本通过批处理调用并由正确的解释器执行,我们可以通过CRON在夜间定时自动处理。没有什么是不可能的!
set_temporary_repository方法
尽管这种配置方法不是强制性的,但我建议每次都使用它,因为在开发阶段,错误和脚本中断并不少见。脚本中断将阻止 "__destruct" 构造函数清理临时文件夹和文件。如果未指定临时文件夹,那么在脚本执行的地方可能会积累大量文件夹。清理专用临时文件夹更容易,尤其是如果可以直接访问(例如资源管理器或SSH)。
要指定临时文件夹的路径,必须在执行脚本时指定。
/** Utiliser le dossier "Temps" pour créer les environnements de travail temporaire **/ $moteur->set_temporary_repository('Temps'); // Pas de slash de fermeture
show_warnings方法
当遇到非阻塞错误时,该错误不会显示。然而,它并不是被忽略的。因此,在您的开发过程中,"show_warnings" 方法允许显示非阻塞错误(即“警告”)。
/** Fin du script : Afficher les warnings rencontrés **/ $moteur->show_warnings();
remove_folder方法
Template 类内置了自己的递归清理文件夹功能,并具有防无限循环的安全系统。与“Help”方法所宣布的不同,这个方法是公开的,这意味着您也可以使用它。
这个函数的优势在于它不仅限于自己的使用。由于您可以选择指定的文件夹,如果需要清理文件夹,它可以承担这个任务,并让您免于编写自己的函数。另外,如果出现错误,您可以使用之前描述的“show_warning”来查找详细信息。
例如,如果一个脚本被中断,并且导致保留临时文件夹和文件,并且您有FTP仅限访问的共享主机,那么这个方法非常有用!
/** "Nettoyage" du dossier temporaire **/ $moteur->remove_folder('Temps');
注意,这个方法会删除指定的文件夹。为了做到这一点,文件夹必须为空,因此需要递归。在一个清理整个文件夹的例子中,您必须确保在后面重新创建它。
/** Re-création du dossier "Temps" **/ mkdir("Temps", 0705);
静态方法strip_blank
使用 Template 类生成 JSON 数据集让我开发了一个静态方法来删除所有空格。
如果您想要一个较小的数据集,请使用 strip_blank 方法。
$json = '{ "ID": 1, "NOM": "DUPRE", "PRENOM": "Nicolas", "AGE": 29 }'; $json = Template::strip_blank($json); # Vaut maintenant '{"ID": 1, "NOM": "DUPRE", "PRENOM": "Nicolas", "AGE": 29}'
静态方法cleanse_js
静态方法 cleanse_js() 允许删除所有符合 JavaScript 规范的注释。
使用 cleanse_js 方法的示例是将一个包含注释的 JSON 文件净化。事实上,JSON 文件不允许有注释,并且不能直接使用 json_decode() 函数解析。
config.app.params.json
/** * Fichier config.app.prams.json * * @author: Nicolas DUPRE * @release: 30/01/2018 * * Fichier de configuration de l'application MCO Scheduler */
# Tenter le code suivant conduirait à un échec : $params = json_decode(file_get_contents('config.app.param.json')); # Executer le code suivant fonctionnerait $params = json_decode( Template::cleanse_js(file_get_contents('config.app.param.json')) );
这个方法还接受一个可选的 $strip_blank 参数,默认值为 false。它允许在删除注释后立即使用 strip_blank 方法。
静态方法cleanse_sql
类似于 cleanse_js 方法,Template 类还有一个静态方法 cleanse_sql,其目的是清理 SQL 文件或文本中的注释。
区别在于,注释是被允许的,并且不一定造成麻烦。然而,使用可选参数 $strip_blank = true,这允许压缩文件。
-- Fichier SQL : schedule-generator.sql -- CREATE TABLE `%SCHEDULE_TABLE%` ( ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, THIS_LAST_CHANGE INT UNSIGNED, SOURCE_ID INT UNSIGNED NOT NULL, SOURCE_LAST_CHANGE INT UNSIGNED, DONE BIT NOT NULL DEFAULT 0, DONE_TIME INT UNSIGNED DEFAULT 0, DONE_BY VARCHAR(15) DEFAULT NULL ); -- voir pour constraint index ALTER TABLE `%SCHEDULE_TABLE%` ADD INDEX (SOURCE_ID);
$moteur->set_template_text( Template::clease_sql(file_get_contents('schedule-generator.sql') ); $PDO->query( $moteur->render()->get_render_content() );
总之
总结本手册,您将找到最重要的点列表
- 该类的作用是分离内容和形式。
- 一个模型包含变量。
- 这些变量的命名是灵活的,尽管某些字符被严格禁止。
- 一个变量由放在其前后的一或多个字符界定。
- 变量后面的字符顺序与在HTML标签中找到的顺序相反。
- 默认分隔符是百分号(%),但可以自定义。
- 通过将变量名与其值关联为“VARIABLE” => “value”的形式,在PHP中发送变量数据。
- 存在一些特定于模型的指令。
- 第一条指令是BEGIN_BLOCK,表示要重复的一组行。
- 块通过一个唯一的名称标识。
- 它的名称允许以“BLOC_NAME” => Array()的形式传递数据。
- 其内容重复的次数与包含“VARIABLE” => “VALEUR”对的数量一样。
- 可以通过双重分隔符从块中访问全局变量。
- 第二条指令允许在条件满足时显示内容。
- 第三条指令允许包含遵循相同规则的自定义模板:INCLUDE_TEMPLETE。
- 第四条指令允许写入PHP代码:BEGIN_PHP。
- 第五条指令允许声明前面提到的块,而不进行解释:BEGIN_DECLARE。
- 所有块都必须通过唯一的名称标识。
- 最后一条指令允许调用已声明或已使用的块:USE。
- 关闭标签的顺序必须严格与打开标签的顺序相反,类似于HTML。
- 该类提供了一个伪全局变量($_PHP),可在BEGIN_PHP块中使用。
- 指令也可以包含变量(除了它们的标识符名称)。
- 这些指令可以相互嵌套。
- 指令前后不得有任何字符,否则可能无法正常工作。最好的情况是,这些字符将不被处理。
- 引擎的最小配置包括其初始化、指定模型和定义输出名称。
- 仅生成文档不会生成任何输出。
- 文档的生成可以是临时的或永久的。
- 在永久模式下,文档被复制到指定的文件夹中。
- 在临时模式下,文档在脚本结束时被构造函数“__destruct”删除。
- 该类提供了对UTF8编码(读和写)的集成管理。
- 它还提供了一些辅助方法,有助于您的开发。
- 最重要的是“help”方法,列出了所有现有方法。



