salesforce/handlebars-php

PHP的Handlebars处理器

3.0.1 2023-01-12 16:24 UTC

This package is not auto-updated.

Last update: 2024-09-20 23:33:59 UTC


README

PHPUnit

#handlebars-php

A simple, logic-less, yet powerful templating engine for PHP

名称: handlebars-php

许可: MIT

需求: PHP >= 5.4

关于Handlebars

Handlebars提供了必要的功能,让您可以有效地构建语义模板,没有任何挫败感,同时将视图和代码分离,就像我们都知道它们应该那样。

分支自: XaminProject的Handlebars.php

Handlebars是Handlebars.js的PHP版本

安装Handlebars

您可以直接下载Handlebars.php,也可以使用Composer。

要使用Composer安装,请将以下内容添加到您的composer.json文件中的require

"salesforce/handlebars-php": "1.*"

composer.json

{
    "name": "myapp/name",
    "description": "My awesome app name",
    "require": {
        "salesforce/handlebars-php": "1.*"
    }
}

入门指南

至少,我们需要有一个数组模型和一个模板字符串。或者我们可以有一个包含handlebars(或html,text等)表达式的文件。

模板

Handlebars模板看起来像常规HTML,其中嵌入handlebars表达式。

Handlebars会将由{{expression}}返回的值进行HTML转义。

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    Hello, my name is {{name}}
  </div>
</div>

上面的字符串可以直接在PHP文件中使用,或者放入一个文件(例如:/templates/main.tpl),在渲染时调用。

PHP文件

现在我们已创建了模板文件,在一个PHP文件(index.php)中,我们将创建传递给模型的数据。模型是一个键/值数组。

以下我们将创建Handlebars对象,设置部分加载器,并在模型中放入一些数据。

/index.php

<?php

# With composer we can autoload the Handlebars package
require_once ("./vendor/autoload.php");

# If not using composer, you can still load it manually.
# require 'src/Handlebars/Autoloader.php';
# Handlebars\Autoloader::register();

use Handlebars\Handlebars;
use Handlebars\Loader\FilesystemLoader;

# Set the partials files
$partialsDir = __DIR__."/templates";
$partialsLoader = new FilesystemLoader($partialsDir,
    [
        "extension" => "html"
    ]
);

# We'll use $handlebars throughout this the examples, assuming the will be all set this way
$handlebars = new Handlebars([
    "loader" => $partialsLoader,
    "partials_loader" => $partialsLoader
]);

# Will render the model to the templates/main.tpl template
$model = [...];
echo $handlebars->render("main", $model);

分配数据

分配数据最简单的方式是创建一个数组模型。该模型将包含所有传递给模板的数据。

<?php

$model = [
    "name" => "Yolo Baggins",
    "title" => "I'm Title",
    "permalink" => "blog/",
    "foo" => "bar",
    "article" => [
        "title" => "My Article Title"
    ],
    "posts" => [
        [
            "title" => "Post #1",
            "id" => 1,
            "content" => "Content"
        ],
        [
            "title" => "Post 2",
            "id" => 2,
            "content" => "Content"
        ]
    ]
];

渲染模板

使用方法Handlebars\Handlebars::render($template, $model)在创建完成后渲染模板。

$template : 模板可以是文件的名称,或者是一个包含handlebars/html的字符串。

$model : 是我们将传递到模板的数组

下面的代码将渲染模型到templates/main.tpl模板

echo $handlebars->render("main", $model);

或者您也可以直接使用$handlebars而不调用render方法

echo $handlebars("main", $model);

表达式

让我们使用以下简单的模型进行以下示例,假设所有内容都已按照上述方式设置。

<?php

$model = [
    "title" => "I'm Title",
    "permalink" => "/blog/",
    "foo" => "bar",
    "article" => [
        "title" => "My Article Title"
    ],
    "posts" => [
        [
            "title" => "Post #1",
            "id" => 1,
            "content" => "Content"
        ],
        [
            "title" => "Post 2",
            "id" => 2,
            "content" => "Content"
        ]
    ]
];

让我们处理模板。

Handlebars表达式是Handlebars模板的基本单元。您可以使用它们单独在{{mustache}}中使用,将它们传递给Handlebars辅助函数,或者将它们用作哈希参数的值。

最简单的Handlebars表达式是一个简单的标识符

{{title}}

-> I'm Title

Handlebars嵌套表达式是点分隔的路径。

{{article.title}}

-> My Article Title

Handlebars数组中的嵌套表达式。

{{posts.0.title}}

-> Post #1

Handlebars还允许通过this引用解决辅助函数和数据字段之间的名称冲突

{{./name}} or {{this/name}} or {{this.name}}

带有辅助函数的Handlebars表达式。在这种情况下,我们使用了upper辅助函数

{{#upper title}}

-> I'M TITLE

嵌套的Handlebars路径也可以包含../段,这些段将对父上下文中的路径进行评估。

{{#each posts}}
    <a href="/posts/{{../permalink}}/{{id}}">{{title}}</a>
    {{content}}
{{/each}}

Handlebars会将由{{expression}}返回的值进行HTML转义。如果您不想让Handlebars转义值,请使用“三重波浪号”,{{{ }}}。

{{{foo}}}

控制结构

if/elseunless控制结构作为常规Handlebars辅助函数实现

IF/ELSE

您可以使用if助手有条件地渲染一个块。如果它的参数返回false、null、""或[](一个"假"值),Handlebars将不会渲染该块。

示例

{{#if isActive}}
    This part will be shown if it is active
{{#else if isValid}}
    This part will be shown if it is valid
{{else}}
    This part will be shown if isActive and isValid are both "falsy" values
{{/if}}
<?php

$model = [
    "isActive" => true,
    "isValid" => false
];

echo $handlebars->render($template, $model);

除非

您可以使用unless助手作为if助手的逆,如果表达式返回一个"假"值,则其块将被渲染。

{{#unless isActive}}
    This part will not show if isActive is true
{{/unless}}

##迭代器:EACH

您可以使用内置的each助手遍历列表。在块内部,您可以使用{{this}}或{{.}}来引用正在迭代的元素。

示例

<h2>All genres:</h2>
{{#each genres}}
    {{.}}
{{/each}}


{{#each cars}}
    <h3>{{category}}</h3>
    Total: {{count}}
    <ul>
    {{#each list}}
        {{.}}
    {{/each}}
    </ul>
{{/each}}
<?php

$model = [
    "genres" => [
        "Hip-Hop",
        "Rap",
        "Techno",
        "Country"
    ],
    "cars" => [
        "category" => "Foreign",
        "count" => 4,
        "list" => [
            "Toyota",
            "Kia",
            "Honda",
            "Mazda"
        ],
        "category" => "WTF",
        "count" => 1,
        "list" => [
            "Fiat"
        ],
        "category" => "Luxury",
        "count" => 2,
        "list" => [
            "Mercedes Benz",
            "BMW"
        ]
    ],
];

    echo $engine->render($template, $model);    

EACH/ELSE

您可以可选地提供一个{{else}}部分,该部分仅在列表为空时显示。

<h2>All genres:</h2>
{{#each genres}}
    {{.}}
{{else}}
    No genres found!
{{/each}}

切片EACH数组[start:end]

(仅PHP)#each助手还具有切片数据的能力

  • {{#each Array[start:end]}} = 从start开始到end -1
  • {{#each Array[start:]}} = 从start开始到数组的其余部分
  • {{#each Array[:end]}} = 从开始到end -1
  • {{#each Array[:]}} = 整个数组的副本
  • {{#each Array[-1]}}
  • {{#each Array[-2:]}} = 最后两个元素
  • {{#each Array[:-2]}} = 除了最后两个元素之外的所有内容
<h2>All genres:</h2>
{{#each genres[0:10]}}
    {{.}}
{{else}}
    No genres found!
{{/each}}

{{@INDEX}}和{{@KEY}}

当在each中循环遍历项目时,您可以选择通过{{@index}}引用当前循环索引。

{{#each array}}
  {{@index}}: {{this}}
{{/each}}


{{#each object}}
  {{@key}}: {{this}}
{{/each}}

更改上下文:WITH

您可以使用内置的with块助手更改模板部分段的上下文。

<?php

$model = [
    "genres" => [
        "Hip-Hop",
        "Rap",
        "Techno",
        "Country"
    ],
    "other_genres" => [
        "genres" => [
        "Hip-Hop",
        "Rap",
        "Techno",
        "Country"
        ]
]
];
<h2>All genres:</h2>
{{#with other_genres}}
{{#each genres}}
    {{.}}
{{/each}}
{{/with}}

Handlebars内置助手

If

{{#if isActive}}
    This part will be shown if it is active
{{#else if isValid}}
    This part will be shown if it is valid
{{else}}
    This part will be shown if isActive and isValid are both "falsy" values
{{/if}}

Unless

{{#unless isActive}}
    This part will show when isActive is false
{{else}}
    Otherwise this one will show
{{/unless}}

Each

{{#each genres[0:10]}}
    {{.}}
{{else}}
    No genres found!
{{/each}}

With

{{#with other_genres}}
{{#each genres}}
    {{.}}
{{/each}}
{{/with}}

其他助手

为了方便,Voodoo\Handlebars添加了一些额外的助手。

Upper

将字符串格式化为大写

{{#upper title}}

Lower

将字符串格式化为小写

{{#lower title}}

Capitalize

将首字母大写

{{#capitalize title}}

Capitalize_Words

将字符串中的每个单词都大写

{{#capitalize_words title}}

Reverse

反转字符串的顺序

{{#reverse title}}

Format_Date

格式化日期:{{#format_date date '$format'}}

{{#format_date date 'Y-m-d H:i:s'}}

Inflect

根据计数将单词变为单数或复数:{{#inflect count $singular $plurial}}

{{#inflect count '%d book' '%d books'}}

Truncate

截断字符串:{{#truncate title $length $ellipsis}}

{{#truncate title 21 '...'}}

Default

如果字符串为空,则使用默认值:{{#default title $defaultValue}}

{{#default title 'No title'}}

Raw

该助手将handlebars表达式原样返回。表达式将不会被解析

{{#raw}}
    {{#each cars}}
        {{model}}
    {{/each}}
{{/raw}}

->

{{#each cars}}
    {{model}}
{{/each}}

Repeat

截断字符串:{{#repeat $count}}{{/repeat}}

{{#repeat 5}}
    Hello World!
{{/repeat}}

变量和块仍然可以使用

{{#repeat 5}}
    Hello {{name}}!
{{/repeat}}

定义/调用

允许定义一个内容块并在以后使用它。这有助于遵循DRY(不要重复自己)原则。

定义

{{#define $definedName}}
    content
{{/define}}

调用

{{#invoke $definedName}}

示例

{{#define hello}}
    Hello World! How do you do?
{{/define}}

{{#invoke hello}}

->

Hello World! How do you do?

模板注释

您可以在handlebars代码中使用注释,就像在您的代码中使用注释一样。由于通常有一些逻辑层次,这是一种良好的做法。

{{!-- only output this author names if an author exists --}}

部分

部分是您可以在主模板中包含的其他模板。

要这样做

{{> my_partial}}

这是一个位于/templates/my_partial.html的文件

编写自己的助手

块助手使您能够定义自定义迭代器和可以以新上下文调用传递的块的助手。

要创建自己的助手,请使用以下方法:Handlebars::addHelper($name, $callback)

以下助手将字符串转换为大写

$handlebars->addHelper("upper",
    function($template, $context, $args, $source){
        return strtoupper($context->get($args));
    }
);

现在我们可以像这样使用这个助手

{{#upper title}}

为#each的数据变量

在Handlebars JS v1.1中,为#each助手添加了数据变量@first@last。由于这些变量与向后兼容性不兼容,这些数据变量默认禁用,并且必须手动启用。

要启用新数据变量,在实例化Handlebars实例时将enableDataVariables选项设置为true

$handlebars = new Handlebars([
    "loader" => $partialsLoader,
    "partials_loader" => $partialsLoader,
    "enableDataVariables" => true
]);

给定以下模板和数据

{{#each data}}{{#if @first}}FIRST: {{/if}}{{this}}<br>{{/each}}
'data' => ['apple', 'banana', 'carrot', 'zucchini']

输出将是

FIRST: apple<br>banana<br>carrot<br>zucchini<br>

给定以下模板和上述数据

{{#each data}}{{@first}}: {{this}}<br>{{/each}}

输出将是

true: apple<br>banana<br>carrot<br>zucchini<br>

数据变量还支持在多个#each语句中的相对引用。给定

{{#each data}}{{#each this}}outer: {{@../first}},inner: {{@first}};{{/each}}{{/each}}
'data' => [['apple', 'banana'], ['carrot', 'zucchini']]

输出将是

outer: true,inner: true;outer: true,inner: false;outer: false,inner: true;outer: false,inner: false;

请注意,当启用数据变量时,以@开头的变量被视为受限制,并将覆盖数据中指定的值。

例如,给定以下模板和以下数据,输出将根据是否启用了数据变量而不同。

{{#each objects}}{{@first}}, {{@last}}, {{@index}}, {{@unknown}}{{/each}}
$object = new stdClass;
$object->{'@first'} = 'apple';
$object->{'@last'} = 'banana';
$object->{'@index'} = 'carrot';
$object->{'@unknown'} = 'zucchini';
$data = ['objects' => [$object]];

$engine = new \Handlebars\Handlebars(array(
    'loader' => new \Handlebars\Loader\StringLoader(),
    'helpers' => new \Handlebars\Helpers(),
    'enableDataVariables'=> $enabled,
));
$engine->render($template, $data)

enableDataVariablesfalse 时,现有行为不变,其中一些变量将被返回。

apple, banana, 0, zucchini

enableDataVariablestrue 时,行为与 HandlebarsJS 1.1 的行为匹配,即所有数据变量将替换数据中定义的变量,任何以 @ 开头且未知的变量将被置为空白。

true, true, 0,

致谢

贡献

欢迎贡献!