# Twig 教程

> 原文： [https://zetcode.com/php/twig/](https://zetcode.com/php/twig/)

Twig 教程展示了如何在 PHP 应用中使用 Twig 模板引擎来生成文档。

## 枝条

Twig 是一个 PHP 模板引擎。 它是由 Symfony 开发人员创建的。 Twig 文件的扩展名为`.html.twig`； 它们是静态数据（例如 HTML 和 Twig 构造）的混合。

Twig 使用双大括号分隔符`{{ }}`进行输出，并使用大括号百分比定界符`{% %}`进行逻辑运算。 `{# #}`用于发表评论。

```php
<ul>
    {% for word in words %}
        <li>{{ word }}</li>
    {% endfor %}
</ul>

```

此代码是示例 Twig 语法。 在此代码中，我们使用`for`标签创建一个循环。

Twig 语法由标签，过滤器，函数，运算符和测试组成。

## 安装 Twig

首先，我们设置了 Twig。

```php
$ composer require twig/twig

```

我们用 Composer 安装 Twig。

```php
$ mkdir templates

```

我们将模板文件放入`template`目录。

```php
require __DIR__ . '/vendor/autoload.php';

```

我们需要将`autoload.php`文件添加到脚本中。

## 模板引擎

模板引擎或模板处理器是一个旨在将模板与数据模型结合以生成文档的库。 模板引擎通常用于在源代码预处理或生成动态 HTML 页面中生成大量电子邮件。

我们创建一个模板引擎，在其中定义静态零件和动态零件。 动态部分随后将替换为数据。 渲染函数随后将模板与数据结合在一起。

## Twig 第一个例子

以下是 Twig 模板系统的简单演示。

`first.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

echo $twig->render('first.html.twig', ['name' => 'John Doe', 
    'occupation' => 'gardener']);

```

我们使用`FilesystemLoader`从指定目录加载模板。

```php
echo $twig->render('first.html.twig', ['name' => 'John Doe', 
    'occupation' => 'gardener']);

```

输出通过`render()`生成。 它带有两个参数：模板文件和数据。

`templates/first.html.twig`

```php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <p>
        {{ name }} is a {{ occupation }}
    </p>

</body>

</html>

```

这是模板文件。 变量以`{{}}`语法输出。

```php
$ php first.php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <p>
        John Doe is a gardener
    </p>

</body>

</html>

```

这是输出。

## Twig 过滤器

过滤器使我们能够以各种方式修改数据。

`filters.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

$words = ['sky', 'mountain', 'falcon', 'forest', 'rock', 'blue'];
$sentence = 'today is a windy day';

echo $twig->render('filters.html.twig', 
    ['words' => $words, 'sentence' => $sentence]);

```

在示例中，我们有一个数组和一个字符串作为模板数据。

`templates/filters.html.twig`

```php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Filters</title>
</head>

<body>

    <p>
     The array has {{ words | length }} elements
    </p>

    <p>
     Joined array elements: {{ words | join(',') }} 
    </p>    

    <p>
     {{ sentence | title }} 
    </p>        

</body>

</html>

```

过滤器应用`|`字符。 该示例使用`length`对单词进行计数，使用`join`连接数组元素，并使用`title`修改字符。

## Twig 自定义过滤器

我们可以使用`Twig_Filter`创建自定义过滤器。

`customfilter.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$twig->addFilter(new Twig_Filter('accFirst', 'accFirst'));

$sentence = 'šumivé víno';

echo $twig->render('customfilter.html.twig',
    ['sentence' => $sentence]);

function accFirst($value, $encoding = 'UTF8')
{
    $strlen = mb_strlen($value, $encoding);
    $firstChar = mb_substr($value, 0, 1, $encoding);
    $rest = mb_substr($value, 1, $strlen - 1, $encoding);

    return mb_strtoupper($firstChar, $encoding) . $rest;
}

```

我们添加了一个名为`accFirst`的新过滤器。 它仅修改第一个字母，也可以处理重音。

`templates/customfilter.html.twig`

```php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Custom filter</title>
</head>

<body>  

    <p>
     {{ sentence | accFirst }} 
    </p>      

</body>

</html>

```

这是模板文件，使用自定义`accFirst`过滤器。

## Twig 循环

要创建循环，我们使用`for`标签。

`looping.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

$words = ['sky', 'mountain', 'falcon', 'forest', 
    'rock', 'blue', 'solid', 'book', 'tree'];

echo $twig->render('words.html.twig', ['words' => $words]);

```

我们将循环一个单词数组。

`templates/words.html.twig`

```php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Words</title>
</head>

<body>

    <ul>
    {% for word in words %}
        <li>{{ word }}</li>
    {% endfor %}
    </ul>

    <ul>
    {% for word in words|slice(2, 4) %}
        <li>{{ word }}</li>
    {% endfor %}    
    </ul>

</body>

</html>

```

在模板文件中，我们遍历`words`数组并生成 HTML 列表。 使用`slice()`过滤器，我们可以遍历数组的一部分。

## Twig 循环和`if else`

我们可以将`for`标签与`if`标签和`else`标签结合在一起。

`looping2.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

$users = [ 
    ['name' => 'John Doe', 'active' => false],
    ['name' => 'Lucy Smith', 'active' => false],
    ['name' => 'Peter Holcombe', 'active' => false],
    ['name' => 'Barry Collins', 'active' => false]
];

echo $twig->render('activeusers.html.twig', ['users' => $users]);

```

我们向模板文件发送用户数组。

`templates/activeusers.html.twig`

```php
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

<p>Active users</p>

<ul>
    {% for user in users if user.active %}
        <li>{{ user.name }}</li>
    {% else %}
        <li>No users found</li>
    {% endfor %}
</ul>

</body>

</html>

```

我们输出的用户名称`user.active`属性为`true`。 当没有活动用户时，将显示`else`标记的输出。

## Twig `set`标签

`set`标签允许将值设置为模板内的变量。

```php
$words = ['sky', 'mountain', 'falcon', 'forest',
    'rock', 'blue', 'solid', 'book', 'tree'];

echo $twig->render('test.html.twig', ['words' => $words]);

```

我们有一个单词表。

```php
{% set sorted = words | sort %}

<ul>
{% for word in sorted %}
    <li>{{ word }}</li>
{% endfor %}
</ul>

```

我们使用`sort`过滤器对数组进行排序，并使用`set`将排序后的数组分配给`sorted`变量。

## Twig `verbatim`标签

`verbatim`将部分标记为不应该分析的原始文本。

```php
{% verbatim %}
    <ul>
    {% for word in words %}
        <li>{{ word }}</li>
    {% endfor %}
    </ul>
{% endverbatim %}

```

例如，如果我们有一个讲解 Twig 标签的教程，则无需分析一部分演示。

## Twig 格式过滤器

`format`过滤器通过替换占位符来格式化给定的字符串。 它的作用类似于`sprintf()`函数。

```php
$name = "John Doe";
$age = 34;

echo $twig->render('formatfil.html.twig', ['name' => $name, 'age' => $age]);

```

我们向模板发送两个变量。

```php
{{ "%s is %d years old" | format(name, age) }}

```

我们使用`format`构建字符串。

## Twig 日期函数

`date()`函数将参数转换为日期以允许进行日期比较。

```php
$user = ['name' => 'John Doe', 'created_at' => '2011/11/10'];

echo $twig->render('datefun.html.twig', ['user' => $user]);

```

用户阵列具有`created_at`键。

```php
{% if date(user.created_at) < date('-5years') %}
    <p>{{ user.name }} is a senior user</p>
{% endif %} 

```

在模板中，我们比较两个日期。

## Twig 自动转义

Twig 自动转义某些字符，例如`<`或`>`。

```php
$twig = new Environment($loader, [
    'autoescape' => false
]);

```

可以使用`autoescape`选项关闭自动转义。

```php
$data = "<script src='http::/example.com/nastyscript.js'></script>";

echo $twig->render('autoescape.html.twig', ['data' => $data]);

```

用户可能会有意向应用添加危险的输入。 通过自动转义可以防止包含未知的 JS 文件。

```php
<p>
The data is {{ data }}
</p>

<p>
The data is {{ data | raw }}
</p>

```

如果启用了自动转义，我们可以使用`raw`过滤器显示原始输入。

```php
<p>
The data is <script src="http:/example.com/nastyscript.js"></script>
</p>

<p>
The data is <script src='http:/example.com/nastyscript.js'></script>
</p>

```

此部分输出显示字符如何转义。

## Twig 测试

Twig 测试允许测试数据。 使用`is`运算符进行测试。

```php
$words = ['', null, 'rock', '   ', 'forest'];
echo $twig->render('tests.html.twig', ['words' => $words]);

```

我们有一个包含空，空和空白元素的单词数组。

```php
<ul>
{% for word in words %}

    {% if word is null %}
    <p>null element</p>
    {% elseif word | trim is empty %}
    <p>Empty element</p>
    {% else %}
    <li>{{ word }}</li>
    {% endif %}

{% endfor %}
</ul>

```

为了处理空，空和空元素，Twig 进行了`empty`和`null`测试。

## Twig 继承

Twig 的模板继承是一项强大的函数，可消除重复并促进维护。

`inheritance.php`

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

echo $twig->render('derived.html.twig');

```

这是`inheritance.php`文件。 它呈现`derived.html.twig`，它从`base.html.twig`扩展。

`templates/base.html.twig`

```php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}{% endblock %}</title>
</head>

<body>

{% block body %}{% endblock %}

</body>

</html>

```

基本布局定义了两个由子代替换的块：`title`和`body`。

`templates/derived.html.twig`

```php
{% extends 'base.html.twig' %}

{% block title %}Some title{% endblock %}

{% block body %}

The body contents

{% endblock %}

```

派生的子模板使用`extends`关键字从基本模板继承。 这两个块定义了自定义文本。

```php
$ php inheritance.php
<!DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">    
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Some title</title>
</head>

<body>

The body contents

</body>

</html>

```

This is the output.

## Symfony 的例子

Twig 是 Symfony 框架的组成部分。 下一个示例显示在 Symfony 骨架应用中使用 Twig 的步骤。

```php
$ composer create-project symfony/skeleton simple
$ cd simple

```

我们创建一个新的 Symfony 框架应用，然后移至项目目录。

```php
$ composer require server --dev

```

我们包括开发服务器。

```php
$ composer require maker annotations twig

```

我们包括一些基本的 Symfony 组件，包括 Twig。

```php
$ php bin/console make:controller HomeController

```

我们创建一个家庭控制器。

`src/Controller/HomeController.php`

```php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class HomeController extends AbstractController
{
    /**
     * @Route("/home", name="home")
     */
    public function index()
    {
        $words = ['sky', 'blue', 'cloud', 'symfony', 'forest'];

        return $this->render('home/index.html.twig', [
            'words' => $words
        ]);
    }
}

```

在家庭控制器中，我们渲染`index.html.twig`模板，并将其传递给`$words`数组进行处理。

`templates/base.html.twig`

```php
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>

```

这是基本布局页面。

`templates/home/index.html.twig`

```php
{% extends 'base.html.twig' %}

{% block title %}Home page{% endblock %}

{% block body %}

<h2>List of words</h2>

<ul>
{% for word in words  %}
    <li>{{ word }}</li>
{% endfor %}
</ul>

{% endblock %}

```

这是主页模板。 它使用`for`标记遍历单词，然后将它们输出到无序列表中。

```php
$ php bin/console server:run

```

我们启动服务器。

我们导航到`http://localhost:8000/home`以查看结果。

在本教程中，我们使用了 Twig 从模板和数据生成文档。 我们介绍了 Twig 标签，过滤器，测试和继承。 我们在 Symfony 应用中显示了 Twing。

您可能也对以下相关教程感兴趣： [PHP Faker 教程](/php/faker/)，[Respect 验证教程](/php/respectvalidation/)， [Symfony 入门](/symfony/intro/)， [Rakit 验证教程](/php/rakitvalidation/) ， [PHP PDO 教程](/php/pdo/)和 [PHP 教程](/lang/php/)。