[TOC]
# Volt:模板引擎
Volt是一種用C語言編寫的超快速且設計友好的模板語言。它為您提供了一組幫助程序,以便以簡單的方式編寫視圖。Volt與Phalcon的其他組件高度集成,就像您可以將其用作應用程序中的獨立組件一樣。

Volt的靈感來自最初由[Armin Ronacher](https://github.com/mitsuhiko)創作的[Jinja](http://jinja.pocoo.org/)。因此,許多開發人員將使用與類似模板引擎相同的語法在熟悉的領域。Volt的語法和功能已經通過更多元素得到增強,當然還有開發人員在使用Phalcon時習慣的性能。
## 介紹
Volt視圖被編譯為純PHP代碼,因此基本上他們省去了手動編寫PHP代碼的工作:
```twig
{# app/views/products/show.volt #}
{% block last_products %}
{% for product in products %}
* Name: {{ product.name|e }}
{% if product.status === 'Active' %}
Price: {{ product.price + product.taxes/100 }}
{% endif %}
{% endfor %}
{% endblock %}
```
## 激活Volt
與其他模板引擎一樣,您可以在視圖組件中注冊Volt,使用新擴展或重用標準`.phtml`:
```php
<?php
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
// Register Volt as a service
$di->set(
'voltService',
function ($view, $di) {
$volt = new Volt($view, $di);
$volt->setOptions(
[
'compiledPath' => '../app/compiled-templates/',
'compiledExtension' => '.compiled',
]
);
return $volt;
}
);
// Register Volt as template engine
$di->set(
'view',
function () {
$view = new View();
$view->setViewsDir('../app/views/');
$view->registerEngines(
[
'.volt' => 'voltService',
]
);
return $view;
}
);
```
使用標準的`.phtml`擴展名:
```php
<?php
$view->registerEngines(
[
'.phtml' => 'voltService',
]
);
```
您無需在DI中指定Volt服務;你也可以使用Volt引擎的默認設置:
```php
<?php
$view->registerEngines(
[
'.volt' => Phalcon\Mvc\View\Engine\Volt::class,
]
);
```
如果您不想將Volt重用為服務,則可以傳遞匿名函數來注冊引擎而不是服務名稱:
```php
<?php
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
// Register Volt as template engine with an anonymous function
$di->set(
'view',
function () {
$view = new View();
$view->setViewsDir('../app/views/');
$view->registerEngines(
[
'.volt' => function ($view, $di) {
$volt = new Volt($view, $di);
// Set some options here
return $volt;
}
]
);
return $view;
}
);
```
Volt提供以下選項:
| 選項 | 描述 | 默認 |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------- |
| `autoescape` | 啟用HTML的全局自動視圖 | `false` |
| `compileAlways` | 如果模板必須在每個請求中編譯或僅在更改時,請告訴Volt | `false` |
| `compiledExtension` | 附加到編譯的PHP文件的附加擴展 | `.php` |
| `compiledPath` | 一個可寫路徑,將放置已編譯的PHP模板 | `./` |
| `compiledSeparator` | Volt用這個分隔符替換目錄分隔符/和\,以便在編譯目錄中創建單個文件| `%%` |
| `prefix` | 允許在編譯路徑中為模板添加前綴 | `null` |
| `stat` | Phalcon是否必須檢查模板文件與其編譯路徑之間是否存在差異 | `true` |
根據上述選項生成編譯路徑,如果開發人員希望完全自由地定義編譯路徑,則可以使用匿名函數生成它,此函數接收視圖目錄中模板的相對路徑。以下示例顯示如何動態更改編譯路徑:
```php
<?php
// Just append the .php extension to the template path
// leaving the compiled templates in the same directory
$volt->setOptions(
[
'compiledPath' => function ($templatePath) {
return $templatePath . '.php';
}
]
);
// Recursively create the same structure in another directory
$volt->setOptions(
[
'compiledPath' => function ($templatePath) {
$dirName = dirname($templatePath);
if (!is_dir('cache/' . $dirName)) {
mkdir('cache/' . $dirName , 0777 , true);
}
return 'cache/' . $dirName . '/'. $templatePath . '.php';
}
]
);
```
## 基本用法
視圖由Volt代碼,PHP和HTML組成。一組特殊分隔符可用于進入伏特模式。`{%...%}`用于執行諸如for循環或賦值和`{{...}}`之類的語句,將表達式的結果打印到模板。
下面是一個最小的模板,它說明了一些基礎知識:
```twig
{# app/views/posts/show.phtml #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }} - An example blog</title>
</head>
<body>
{% if show_navigation %}
<ul id='navigation'>
{% for item in menu %}
<li>
<a href='{{ item.href }}'>
{{ item.caption }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
<h1>{{ post.title }}</h1>
<div class='content'>
{{ post.content }}
</div>
</body>
</html>
```
使用`Phalcon\Mvc\View` 可以將變量從控制器傳遞到視圖。在上面的例子中,四個變量被傳遞給視圖:`show_navigation`,`menu`,`title`和`post`:
```php
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function showAction()
{
$post = Post::findFirst();
$menu = Menu::findFirst();
$this->view->show_navigation = true;
$this->view->menu = $menu;
$this->view->title = $post->title;
$this->view->post = $post;
// Or...
$this->view->setVar('show_navigation', true);
$this->view->setVar('menu', $menu);
$this->view->setVar('title', $post->title);
$this->view->setVar('post', $post);
}
}
```
## 變量
對象變量可能具有可使用以下語法訪問的屬性:`foo.bar`。如果要傳遞數組,則必須使用方括號語法:`foo ['bar']`
```twig
{{ post.title }} {# for $post->title #}
{{ post['title'] }} {# for $post['title'] #}
```
## 過濾
可以使用過濾器格式化或修改變量。管道操作`|`用于將過濾器應用于變量:
```twig
{{ post.title|e }}
{{ post.content|striptags }}
{{ name|capitalize|trim }}
```
以下是Volt中可用的內置過濾器列表:
| 過濾 | 描述 |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `abs` | 將[abs](http://php.net/manual/en/function.abs.php) PHP函數應用于值。 |
| `capitalize` | 通過將[ucwords](http://php.net/manual/en/function.ucwords.php) PHP函數應用于值來大寫字符串 |
| `convert_encoding` | 將字符串從一個字符集轉換為另一個字符集 |
| `default` | 如果計算的表達式為空(未設置或計算為false值),則設置默認值 |
| `e` | 將 `Phalcon\Escaper->escapeHtml()` 應用于該值 |
| `escape` | 將 `Phalcon\Escaper->escapeHtml()` 應用于該值 |
| `escape_attr` | 將 `Phalcon\Escaper->escapeHtmlAttr()` 應用于該值 |
| `escape_css` | 將 `Phalcon\Escaper->escapeCss()` 應用于該值 |
| `escape_js` | 將 `Phalcon\Escaper->escapeJs()` 應用于該值 |
| `format` | 使用 [sprintf](http://php.net/manual/en/function.sprintf.php) 格式化字符串。 |
| `json_encode` | 將值轉換為其[JSON](http://php.net/manual/en/function.json-encode.php)表示形式 |
| `json_decode` | 將值從其[JSON](http://php.net/manual/en/function.json-encode.php)表示轉換為PHP表示 |
| `join` | 使用分隔符[join](http://php.net/manual/en/function.join.php)來連接數組部件 |
| `keys` | 使用[array_keys](http://php.net/manual/en/function.array-keys.php)返回數組鍵 |
| `left_trim` | 將[ltrim](http://php.net/manual/en/function.ltrim.php) PHP函數應用于該值。刪除多余的空格 |
| `length` | 計算字符串長度或數組或對象中的項目數 |
| `lower` | 將字符串的大小寫更改為小寫 |
| `nl2br` | 通過換行符 `\n`更改換行符(`<br />`)。使用PHP函數[nl2br](http://php.net/manual/en/function.nl2br.php)|
| `right_trim` | 將[rtrim](http://php.net/manual/en/function.rtrim.php) PHP函數應用于該值。刪除多余的空格 |
| `sort` | 使用PHP函數asort [asort](http://php.net/manual/en/function.asort.php) 對數組進行排序 |
| `stripslashes` | 將[stripslashes](http://php.net/manual/en/function.stripslashes.php) PHP函數應用于該值。刪除轉義的引號 |
| `striptags` | 將[strip_tags](http://php.net/manual/en/function.strip-tags.php) PHP函數應用于值。刪除HTML標記 |
| `trim` | 將[trim](http://php.net/manual/en/function.trim.php)PHP函數應用于該值。刪除多余的空格 |
| `upper` | 將字符串的大小寫更改為大寫 |
| `url_encode` | 將[urlencode](http://php.net/manual/en/function.urlencode.php) PHP函數應用于該值 |
例子:
```twig
{# e or escape filter #}
{{ '<h1>Hello<h1>'|e }}
{{ '<h1>Hello<h1>'|escape }}
{# trim filter #}
{{ ' hello '|trim }}
{# striptags filter #}
{{ '<h1>Hello<h1>'|striptags }}
{# slashes filter #}
{{ ''this is a string''|slashes }}
{# stripslashes filter #}
{{ '\'this is a string\''|stripslashes }}
{# capitalize filter #}
{{ 'hello'|capitalize }}
{# lower filter #}
{{ 'HELLO'|lower }}
{# upper filter #}
{{ 'hello'|upper }}
{# length filter #}
{{ 'robots'|length }}
{{ [1, 2, 3]|length }}
{# nl2br filter #}
{{ 'some\ntext'|nl2br }}
{# sort filter #}
{% set sorted = [3, 1, 2]|sort %}
{# keys filter #}
{% set keys = ['first': 1, 'second': 2, 'third': 3]|keys %}
{# join filter #}
{% set joined = 'a'..'z'|join(',') %}
{# format filter #}
{{ 'My real name is %s'|format(name) }}
{# json_encode filter #}
{% set encoded = robots|json_encode %}
{# json_decode filter #}
{% set decoded = '{'one':1,'two':2,'three':3}'|json_decode %}
{# url_encode filter #}
{{ post.permanent_link|url_encode }}
{# convert_encoding filter #}
{{ 'désolé'|convert_encoding('utf8', 'latin1') }}
```
## 注釋
也可以使用 `{# ... #}` 分隔符將注釋添加到模板中。其中的所有文本都在最終輸出中被忽略:
```twig
{# note: this is a comment
{% set price = 100; %}
#}
```
## 控制結構列表
Volt提供了一組基本但功能強大的控件結構,可用于模板:
### For
循環遍歷序列中的每個項目。以下示例顯示如何遍歷一組“robots”并打印他/她的名字:
```twig
<h1>Robots</h1>
<ul>
{% for robot in robots %}
<li>
{{ robot.name|e }}
</li>
{% endfor %}
</ul>
```
for循環也可以嵌套:
```twig
<h1>Robots</h1>
{% for robot in robots %}
{% for part in robot.parts %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% endfor %}
{% endfor %}
```
您可以使用以下語法獲取PHP副本中的元素`keys`:
```twig
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for name, value in numbers %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
```
可以選擇設置`if`判斷:
```twig
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for value in numbers if value < 2 %}
Value: {{ value }}
{% endfor %}
{% for name, value in numbers if name !== 'two' %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
```
如果在`for`中定義了`else`,則在迭代器中的表達式導致零迭代時將執行:
```twig
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% else %}
There are no robots to show
{% endfor %}
```
替代語法:
```twig
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% elsefor %}
There are no robots to show
{% endfor %}
```
### 循環控制
`break` 和 `continue` 語句可用于退出循環或強制當前塊中的迭代:
```twig
{# skip the even robots #}
{% for index, robot in robots %}
{% if index is even %}
{% continue %}
{% endif %}
...
{% endfor %}
```
```twig
{# exit the foreach on the first even robot #}
{% for index, robot in robots %}
{% if index is even %}
{% break %}
{% endif %}
...
{% endfor %}
```
### If
作為PHP,`if`語句檢查表達式是否被評估為true或false:
```twig
<h1>Cyborg Robots</h1>
<ul>
{% for robot in robots %}
{% if robot.type === 'cyborg' %}
<li>{{ robot.name|e }}</li>
{% endif %}
{% endfor %}
</ul>
```
else子句也支持:
```twig
<h1>Robots</h1>
<ul>
{% for robot in robots %}
{% if robot.type === 'cyborg' %}
<li>{{ robot.name|e }}</li>
{% else %}
<li>{{ robot.name|e }} (not a cyborg)</li>
{% endif %}
{% endfor %}
</ul>
```
`elseif`控制流結構可以與`if`一起使用來`switch`開關塊:
```twig
{% if robot.type === 'cyborg' %}
Robot is a cyborg
{% elseif robot.type === 'virtual' %}
Robot is virtual
{% elseif robot.type === 'mechanical' %}
Robot is mechanical
{% endif %}
```
### Switch
`if`語句的替代方法是`switch`,允許您在應用程序中創建邏輯執行路徑:
```twig
{% switch foo %}
{% case 0 %}
{% case 1 %}
{% case 2 %}
"foo" is less than 3 but not negative
{% break %}
{% case 3 %}
"foo" is 3
{% break %}
{% default %}
"foo" is {{ foo }}
{% endswitch %}
```
`switch`語句執行語句,因此在某些情況下`break`語句是必需的。`switch`語句和第一個`case` 之間的任何輸出(包括空格)都將導致語法錯誤。因此可以清除空行和空格以減少此處的錯誤數量 [看這里](http://php.net/control-structures.alternative-syntax)。
#### `case` 不帶 `switch`
```twig
{% case EXPRESSION %}
```
將拋出致命錯誤:未捕獲的`Fatal error: Uncaught Phalcon\Mvc\View\Exception: Unexpected CASE`:意外的CASE。
#### `switch` 不帶 `endswitch`
```twig
{% switch EXPRESSION %}
```
將拋出致命錯誤:未捕獲的`Fatal error: Uncaught Phalcon\Mvc\View\Exception: Syntax error, unexpected EOF in ..., there is a 'switch' block without 'endswitch'`:語法錯誤,意外的EOF在......中,有一個'switch'塊沒有'endswitch'。
#### `default` 不帶 `switch`
```twig
{% default %}
```
不會拋出錯誤,因為`default`是過濾器的保留字像`{{ EXPRESSION | default(VALUE) }}`但在這種情況下,表達式只會輸出一個空的字符''。
#### 嵌套 `switch`
```twig
{% switch EXPRESSION %}
{% switch EXPRESSION %}
{% endswitch %}
{% endswitch %}
```
將拋出致命錯誤:未捕獲的`Fatal error: Uncaught Phalcon\Mvc\View\Exception: A nested switch detected. There is no nested switch-case statements support in ... on line ...`:檢測到嵌套switch。在行...不支持嵌套的switch-case語句...
#### `switch` 不帶表達式
```twig
{% switch %}
{% case EXPRESSION %}
{% break %}
{% endswitch %}
```
將拋出致命錯誤:未捕獲的`Fatal error: Uncaught Phalcon\Mvc\View\Exception: Syntax error, unexpected token %} in ... on line ...`:語法錯誤,意外的令牌%}在......在行...
### 循環上下文
一個特殊的變量可用于`for`循環內部,為您提供有關的信息
| 變量 | 描述 |
| ---------------- | ------------------------------------------------------------- |
| `loop.index` | 循環的當前迭代。(1索引) |
| `loop.index0` | 循環的當前迭代。(0索引) |
| `loop.revindex` | 循環結束時的迭代次數(1索引) |
| `loop.revindex0` | 循環結束時的迭代次數(0索引) |
| `loop.first` | 如果在第一次迭代中為true。 |
| `loop.last` | 如果在最后一次迭代中為true。 |
| `loop.length` | 要迭代的項目數 |
例子:
```twig
{% for robot in robots %}
{% if loop.first %}
<table>
<tr>
<th>#</th>
<th>Id</th>
<th>Name</th>
</tr>
{% endif %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ robot.id }}</td>
<td>{{ robot.name }}</td>
</tr>
{% if loop.last %}
</table>
{% endif %}
{% endfor %}
```
## 賦值
可以使用指令'set'在模板中更改變量:
```twig
{% set fruits = ['Apple', 'Banana', 'Orange'] %}
{% set name = robot.name %}
```
同一指令允許多次分配:
```twig
{% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %}
```
此外,您可以使用復合賦值運算符:
```twig
{% set price += 100.00 %}
{% set age *= 5 %}
```
以下操作可用:
| 操作符 | 描述 |
| -------- | ------------------------- |
| `=` | 標準賦值 |
| `+=` | 加等賦值 |
| `-=` | 減等賦值 |
| `*=` | 乘等賦值 |
| `/=` | 除等賦值 |
## 表達式
Volt提供了一組基本的表達式支持,包括文字和常用運算符。可以使用`{{`和`}}`分隔符評估和打印表達式:
```twig
{{ (1 + 1) * 2 }}
```
如果需要在不打印的情況下計算表達式,則可以使用`do`語句:
```twig
{% do (1 + 1) * 2 %}
```
### 字面量
支持以下字面量:
| Filter | 描述 |
| -------------------- | ------------------------------------------------------------------ |
| `'this is a string'` |雙引號或單引號之間的文本作為字符串處理 |
| `100.25` | 帶小數部分的數字作為雙精度/浮點數處理 |
| `100` |沒有小數部分的數字作為整數處理 |
| `false` | 常量'false'是布爾值false |
| `true` | 常量'true'是布爾值true |
| `null` | 常量'null'是Null值 |
### 數組
無論您使用的是PHP 5.3還是 >= 5.4,您都可以通過在方括號中包含值列表來創建數組:
```twig
{# Simple array #}
{{ ['Apple', 'Banana', 'Orange'] }}
{# Other simple array #}
{{ ['Apple', 1, 2.5, false, null] }}
{# Multi-Dimensional array #}
{{ [[1, 2], [3, 4], [5, 6]] }}
{# Hash-style array #}
{{ ['first': 1, 'second': 4/2, 'third': '3'] }}
```
大括號也可用于定義數組或哈希:
```twig
{% set myArray = {'Apple', 'Banana', 'Orange'} %}
{% set myHash = {'first': 1, 'second': 4/2, 'third': '3'} %}
```
### 數學運算
您可以使用以下運算符在模板中進行計算:
| 操作符 | 描述 |
|:--------:| ----------------------------------------------------------------------- |
| `+` | 執行加法操作 `{{ 2 + 3 }}` 返回 5 |
| `-` | 執行減法操作 `{{ 2 - 3 }}` 返回 -1 |
| `*` | 執行乘法操作 `{{ 2 * 3 }}` 返回 6 |
| `/` | 執行除法操作 `{{ 10 / 2 }}` 返回 5 |
| `%` | 執行取余操作 `{{ 10 % 3 }}` 返回 1 |
### 比較運算
以下比較運算符可用:
| 操作符 | 描述 |
|:----------:| ----------------------------------------------------------------- |
| `==` | 檢查兩個操作數是否相等 |
| `!=` | 檢查兩個操作數是否不相等 |
| `<>` | 檢查兩個操作數是否不相等 |
| `>` | 檢查左操作數是否大于右操作數 |
| `<` | 檢查左操作數是否小于右操作數 |
| `<=` | 檢查左操作數是否小于等于于右操作數 |
| `>=` | 檢查左操作數是否大于等于右操作數 |
| `===` | 檢查兩個操作數是否全等 |
| `!==` | 檢查兩個操作數是否不全等 |
### 邏輯運算
邏輯運算符在`if`表達式求值中用于組合多個測試:
| 操作符 | 描述 |
|:----------:| ----------------------------------------------------------------- |
| `or` | 邏輯或 |
| `and` | 邏輯與 |
| `not` | 邏輯非 |
| `( expr )` | 括號組表達式 |
### 其他操作符
其他操作符可以看到以下操作符:
| 操作符 | 描述 |
| ----------------- | ------------------------------------------------------------------------------- |
| `~` | 連接兩個操作數 `{{ 'hello ' ~ 'world' }}` |
| `|` | 在左側的右操作數中應用過濾器`{{ 'hello'|uppercase }}` |
| `..` | 創建一個范圍 `{{ 'a'..'z' }}` `{{ 1..10 }}` |
| `is` | 與==(等于)相同,也執行檢測 |
| `in` | 檢測一個表達式是否被另一個表達式包含在內 `if 'a' in 'abc'` |
| `is not` | 與!=相同(不等于) |
| `'a' ? 'b' : 'c'` | 三元運算符。與PHP三元運算符相同 |
| `++` | 遞增一個值 |
| `--` | 遞減一個值 |
以下示例顯示如何使用運算符:
```twig
{% set robots = ['Voltron', 'Astro Boy', 'Terminator', 'C3PO'] %}
{% for index in 0..robots|length %}
{% if robots[index] is defined %}
{{ 'Name: ' ~ robots[index] }}
{% endif %}
{% endfor %}
```
## 檢測
檢測可用于檢測變量是否具有有效的預期值。運算符`is` 用于執行檢測:
```twig
{% set robots = ['1': 'Voltron', '2': 'Astro Boy', '3': 'Terminator', '4': 'C3PO'] %}
{% for position, name in robots %}
{% if position is odd %}
{{ name }}
{% endif %}
{% endfor %}
```
Volt提供以下內置檢測:
| 檢測 | 描述 |
| ------------- | -------------------------------------------------------------------- |
| `defined` | 檢查是否定義了變量(`isset()`) |
| `divisibleby` | 檢查值是否可以被其他值整除 |
| `empty` | 檢查變量是否為空 |
| `even` | 檢查數值是否是偶數 |
| `iterable` | 檢查值是否可迭代。可以通過'for'語句遍歷 |
| `numeric` | 檢查值是否為數字 |
| `odd` | 檢查數值是否是奇數 |
| `sameas` | 檢查值是否與其他值相同 |
| `scalar` | 檢查值是否為標量(不是數組或對象) |
| `type` | 檢查值是否為指定類型 |
更多示例:
```twig
{% if robot is defined %}
The robot variable is defined
{% endif %}
{% if robot is empty %}
The robot is null or isn't defined
{% endif %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 3: 'Bender'] %}
{% if key is even %}
{{ name }}
{% endif %}
{% endfor %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 3: 'Bender'] %}
{% if key is odd %}
{{ name }}
{% endif %}
{% endfor %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 'third': 'Bender'] %}
{% if key is numeric %}
{{ name }}
{% endif %}
{% endfor %}
{% set robots = [1: 'Voltron', 2: 'Astroy Boy'] %}
{% if robots is iterable %}
{% for robot in robots %}
...
{% endfor %}
{% endif %}
{% set world = 'hello' %}
{% if world is sameas('hello') %}
{{ 'it's hello' }}
{% endif %}
{% set external = false %}
{% if external is type('boolean') %}
{{ 'external is false or true' }}
{% endif %}
```
## 宏
宏可用于在模板中重用邏輯,它們充當PHP函數,可以接收參數并返回值:
```twig
{# Macro 'display a list of links to related topics' #}
{%- macro related_bar(related_links) %}
<ul>
{%- for link in related_links %}
<li>
<a href='{{ url(link.url) }}' title='{{ link.title|striptags }}'>
{{ link.text }}
</a>
</li>
{%- endfor %}
</ul>
{%- endmacro %}
{# Print related links #}
{{ related_bar(links) }}
<div>This is the content</div>
{# Print related links again #}
{{ related_bar(links) }}
```
調用宏時,可以按名稱傳遞參數:
```twig
{%- macro error_messages(message, field, type) %}
<div>
<span class='error-type'>{{ type }}</span>
<span class='error-field'>{{ field }}</span>
<span class='error-message'>{{ message }}</span>
</div>
{%- endmacro %}
{# Call the macro #}
{{ error_messages('type': 'Invalid', 'message': 'The name is invalid', 'field': 'name') }}
```
宏可以返回值:
```twig
{%- macro my_input(name, class) %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
```
并接收可選參數:
```twig
{%- macro my_input(name, class='input-text') %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name') ~ '</p>' }}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
```
## 使用標簽助手
Volt與`Phalcon\Tag`高度集成,因此可以很容易地使用Volt模板中該組件提供的幫助程序:
```twig
{{ javascript_include('js/jquery.js') }}
{{ form('products/save', 'method': 'post') }}
<label for='name'>Name</label>
{{ text_field('name', 'size': 32) }}
<label for='type'>Type</label>
{{ select('type', productTypes, 'using': ['id', 'name']) }}
{{ submit_button('Send') }}
{{ end_form() }}
```
生成以下PHP:
```php
<?php echo Phalcon\Tag::javascriptInclude('js/jquery.js') ?>
<?php echo Phalcon\Tag::form(array('products/save', 'method' => 'post')); ?>
<label for='name'>Name</label>
<?php echo Phalcon\Tag::textField(array('name', 'size' => 32)); ?>
<label for='type'>Type</label>
<?php echo Phalcon\Tag::select(array('type', $productTypes, 'using' => array('id', 'name'))); ?>
<?php echo Phalcon\Tag::submitButton('Send'); ?>
{{ end_form() }}
```
要調用`Phalcon\Tag`幫助程序,您只需要調用該方法的未完整版本:
| 方法 | Volt 函數 |
| --------------------------------- | -------------------- |
| `Phalcon\Tag::checkField` | `check_field` |
| `Phalcon\Tag::dateField` | `date_field` |
| `Phalcon\Tag::emailField` | `email_field` |
| `Phalcon\Tag::endForm` | `end_form` |
| `Phalcon\Tag::fileField` | `file_field` |
| `Phalcon\Tag::form` | `form` |
| `Phalcon\Tag::friendlyTitle` | `friendly_title` |
| `Phalcon\Tag::getTitle` | `get_title` |
| `Phalcon\Tag::hiddenField` | `hidden_field` |
| `Phalcon\Tag::image` | `image` |
| `Phalcon\Tag::javascriptInclude` | `javascript_include` |
| `Phalcon\Tag::linkTo` | `link_to` |
| `Phalcon\Tag::numericField` | `numeric_field` |
| `Phalcon\Tag::passwordField` | `password_field` |
| `Phalcon\Tag::radioField` | `radio_field` |
| `Phalcon\Tag::select` | `select` |
| `Phalcon\Tag::selectStatic` | `select_static` |
| `Phalcon\Tag::stylesheetLink` | `stylesheet_link` |
| `Phalcon\Tag::submitButton` | `submit_button` |
| `Phalcon\Tag::textArea` | `text_area` |
| `Phalcon\Tag::textField` | `text_field` |
## 函數
Volt提供以下內置函數:
| 名稱 | 描述 |
| ------------- | ----------------------------------------------------------- |
| `content` | 包括在先前渲染階段中生成的內容 |
| `get_content` | 與 `content` 相同 |
| `partial` | 動態加載當前模板中的局部視圖 |
| `super` | 渲染父塊的內容 |
| `time` | 使用相同的名稱調用PHP函數 |
| `date` | 使用相同的名稱調用PHP函數 |
| `dump` | 調用PHP函數 `var_dump()` |
| `version` | 返回框架的當前版本 |
| `constant` | 讀取PHP常量 |
| `url` | 使用“url”服務生成URL |
## 集成視圖
此外,Volt與`Phalcon\Mvc\View`集成,您可以使用視圖層次結構并包含部分:
```twig
{{ content() }}
<!-- Simple include of a partial -->
<div id='footer'>{{ partial('partials/footer') }}</div>
<!-- Passing extra variables -->
<div id='footer'>{{ partial('partials/footer', ['links': links]) }}</div>
```
部分包含在運行時,Volt還提供`include`,這將編譯視圖的內容并返回其內容作為視圖的一部分,其中包括:
```twig
{# Simple include of a partial #}
<div id='footer'>
{% include 'partials/footer' %}
</div>
{# Passing extra variables #}
<div id='footer'>
{% include 'partials/footer' with ['links': links] %}
</div>
```
### Include
`include`有一個特殊的行為,可以幫助我們在使用Volt時稍微提高性能,如果在包含文件時指定擴展名并且在編譯模板時它存在,Volt可以內聯包含它的父模板中的模板內容。如果`包含`傳遞的變量,則不會`內聯模板`:
```twig
{# The contents of 'partials/footer.volt' is compiled and inlined #}
<div id='footer'>
{% include 'partials/footer.volt' %}
</div>
```
### Partial vs Include
選擇使用`partial`或`include`時要記住以下幾點:
| 類型 | 描述 |
| ---------- | ---------------------------------------------------------------------------------------------------------- |
| `partial` |允許您包含在Volt和其他模板引擎中制作的模板 |
| | 允許您傳遞類似變量的表達式,允許動態包含其他視圖的內容 |
| | 如果您必須包含的內容經常更改,則會更好 |
| `includes` | 將已編譯的內容復制到視圖中,從而提高性能 |
| | 僅允許包含使用Volt制作的模板 |
| | 在編譯時需要現有模板 |
## 模板繼承
使用模板繼承,您可以創建可由其他模板擴展的基本模板,從而允許重用代碼。基本模板定義的`塊`可以被子模板覆蓋。讓我們假設我們有以下基本模板:
```twig
{# templates/base.volt #}
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel='stylesheet' href='style.css' />
{% endblock %}
<title>{% block title %}{% endblock %} - My Webpage</title>
</head>
<body>
<div id='content'>{% block content %}{% endblock %}</div>
<div id='footer'>
{% block footer %}© Copyright 2015, All rights reserved.{% endblock %}
</div>
</body>
</html>
```
從其他模板我們可以擴展基礎模板替換塊:
```twig
{% extends 'templates/base.volt' %}
{% block title %}Index{% endblock %}
{% block head %}<style type='text/css'>.important { color: #336699; }</style>{% endblock %}
{% block content %}
<h1>Index</h1>
<p class='important'>Welcome on my awesome homepage.</p>
{% endblock %}
```
并非所有塊都必須在子模板中替換,只能替換所需的塊。產生的最終結果如下:
```html
<!DOCTYPE html>
<html>
<head>
<style type='text/css'>.important { color: #336699; }</style>
<title>Index - My Webpage</title>
</head>
<body>
<div id='content'>
<h1>Index</h1>
<p class='important'>Welcome on my awesome homepage.</p>
</div>
<div id='footer'>
© Copyright 2015, All rights reserved.
</div>
</body>
</html>
```
### 多重繼承
擴展模板可以擴展其他模板。以下示例說明了這一點:
```twig
{# main.volt #}
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
```
模板 `layout.volt` 繼承 `main.volt`
```twig
{# layout.volt #}
{% extends 'main.volt' %}
{% block content %}
<h1>Table of contents</h1>
{% endblock %}
```
最后一個繼承`layout.volt`的視圖:
```twig
{# index.volt #}
{% extends 'layout.volt' %}
{% block content %}
{{ super() }}
<ul>
<li>Some option</li>
<li>Some other option</li>
</ul>
{% endblock %}
```
渲染`index.volt`生成:
```html
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Table of contents</h1>
<ul>
<li>Some option</li>
<li>Some other option</li>
</ul>
</body>
</html>
```
注意函數 `super()`的調用。使用該函數,可以呈現父塊的內容。作為partials,設置為`extends`的路徑是當前視圖目錄下的相對路徑(即`app/views/`)。
>[warning] 默認情況下,出于性能原因,Volt僅檢查子模板中的更改以了解何時再次重新編譯為純PHP,因此建議使用選項`'compileAlways'=> true`初始化Volt。因此,編譯模板時始終考慮父模板中的更改。
## 自動轉義模式
您可以使用自動轉義模式啟用塊中打印的所有變量的自動轉義:
```twig
Manually escaped: {{ robot.name|e }}
{% autoescape true %}
Autoescaped: {{ robot.name }}
{% autoescape false %}
No Autoescaped: {{ robot.name }}
{% endautoescape %}
{% endautoescape %}
```
## 擴展Volt
與其他模板引擎不同,Volt本身不需要運行已編譯的模板。編譯模板后,不依賴于Volt。考慮到性能獨立性,Volt僅作為PHP模板的編譯器。
Volt編譯器允許您擴展它,為現有的添加更多函數,檢測或過濾器。
### Functions
函數充當普通的PHP函數,函數名稱需要有效的字符串名稱。可以使用兩種策略添加函數,返回簡單字符串或使用匿名函數。始終要求所選策略返回有效的PHP字符串表達式:
```php
<?php
use Phalcon\Mvc\View\Engine\Volt;
$volt = new Volt($view, $di);
$compiler = $volt->getCompiler();
// This binds the function name 'shuffle' in Volt to the PHP function 'str_shuffle'
$compiler->addFunction('shuffle', 'str_shuffle');
```
使用匿名函數注冊該函數。這種情況我們使用 `$resolvedArgs`來傳遞與參數中傳遞完全相同的參數:
```php
<?php
$compiler->addFunction(
'widget',
function ($resolvedArgs, $exprArgs) {
return 'MyLibrary\Widgets::get(' . $resolvedArgs . ')';
}
);
```
獨立處理參數而未解決:
```php
<?php
$compiler->addFunction(
'repeat',
function ($resolvedArgs, $exprArgs) use ($compiler) {
// Resolve the first argument
$firstArgument = $compiler->expression($exprArgs[0]['expr']);
// Checks if the second argument was passed
if (isset($exprArgs[1])) {
$secondArgument = $compiler->expression($exprArgs[1]['expr']);
} else {
// Use '10' as default
$secondArgument = '10';
}
return 'str_repeat(' . $firstArgument . ', ' . $secondArgument . ')';
}
);
```
根據某些函數可用性生成代碼:
```php
<?php
$compiler->addFunction(
'contains_text',
function ($resolvedArgs, $exprArgs) {
if (function_exists('mb_stripos')) {
return 'mb_stripos(' . $resolvedArgs . ')';
} else {
return 'stripos(' . $resolvedArgs . ')';
}
}
);
```
可以覆蓋內置函數,添加一個有名稱的函數:
```php
<?php
// Replace built-in function dump
$compiler->addFunction('dump', 'print_r');
```
### 過濾器
A filter has the following form in a template: leftExpr|name(optional-args). Adding new filters is similar as seen with the functions:
過濾器在模板中具有以下形式:`左側表達式|名稱(可選參數)`。添加新過濾器與功能類似:
```php
<?php
// This creates a filter 'hash' that uses the PHP function 'md5'
$compiler->addFilter('hash', 'md5');
```
```php
<?php
$compiler->addFilter(
'int',
function ($resolvedArgs, $exprArgs) {
return 'intval(' . $resolvedArgs . ')';
}
);
```
可以覆蓋內置過濾器,添加函數的名稱:
```php
<?php
// Replace built-in filter 'capitalize'
$compiler->addFilter('capitalize', 'lcfirst');
```
### 擴展
通過擴展,開發人員可以更靈活地擴展模板引擎,覆蓋特定指令的編譯,更改表達式或運算符的行為,添加函數/過濾器等。
擴展是一個實現由Volt觸發的事件作為其自身方法的類。例如,下面的類允許在Volt中使用任何PHP函數:
```php
<?php
class PhpFunctionExtension
{
/**
* This method is called on any attempt to compile a function call
*/
public function compileFunction($name, $arguments)
{
if (function_exists($name)) {
return $name . '('. $arguments . ')';
}
}
}
```
上面的類實現了方法`compileFunction`,它在任何嘗試在任何模板中編譯函數調用之前調用。擴展的目的是驗證要編譯的函數是否是允許從模板調用它的PHP函數。擴展中的事件必須返回有效的PHP代碼,這將用作編譯的結果而不是Volt生成的代碼。如果事件未返回字符串,則使用引擎提供的默認行為完成編譯。
以下編譯事件可在擴展中實現:
| 事件/方法 | 描述 |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| `compileFunction` | 在嘗試編譯模板中的任何函數調用之前觸發 |
| `compileFilter` | 在嘗試編譯模板中的任何過濾器調用之前觸發 |
| `resolveExpression` | 在嘗試編譯任何表達式之前觸發。這允許開發人員覆蓋運算符 |
| `compileStatement` | 在嘗試編譯任何表達式之前觸發。這允許開發人員覆蓋任何語句 |
Volt擴展必須在編譯器中注冊,使它們在編譯時可用:
```php
<?php
// Register the extension in the compiler
$compiler->addExtension(
new PhpFunctionExtension()
);
```
## 緩存視圖片段
使用Volt,它可以輕松緩存視圖片段。此緩存可提高性能,防止每次顯示視圖時PHP的內容都被執行:
```twig
{% cache 'sidebar' %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
```
設置特定的秒數:
```twig
{# cache the sidebar by 1 hour #}
{% cache 'sidebar' 3600 %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
```
任何有效的表達式都可以用作緩存鍵:
```twig
{% cache ('article-' ~ post.id) 3600 %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endcache %}
```
緩存由`Phalcon\Cache`組件通過視圖組件完成。在緩存視圖片段部分中了解有關此集成的工作原理的更多信息。
## 將服務注入模板
如果服務容器(DI)可用于Volt,則只需訪問模板中的服務名稱即可使用服務:
```twig
{# Inject the 'flash' service #}
<div id='messages'>{{ flash.output() }}</div>
{# Inject the 'security' service #}
<input type='hidden' name='token' value='{{ security.getToken() }}'>
```
## 獨立組件
在獨立模式下使用Volt可以在下面演示:
```php
<?php
use Phalcon\Mvc\View\Engine\Volt\Compiler as VoltCompiler;
// Create a compiler
$compiler = new VoltCompiler();
// Optionally add some options
$compiler->setOptions(
[
// ...
]
);
// Compile a template string returning PHP code
echo $compiler->compileString(
"{{ 'hello' }}"
);
// Compile a template in a file specifying the destination file
$compiler->compileFile(
'layouts/main.volt',
'cache/layouts/main.volt.php'
);
// Compile a template in a file based on the options passed to the compiler
$compiler->compile(
'layouts/main.volt'
);
// Require the compiled templated (optional)
require $compiler->getCompiledTemplatePath();
```
## 外部資源
* Sublime/Textmate的插件包可在[此處](https://github.com/phalcon/volt-sublime-textmate)獲得
* [Album-O-Rama](https://album-o-rama.phalconphp.com)是一個使用Volt作為模板引擎的示例應用程序, [Github](https://github.com/phalcon/album-o-rama)
* [官方站點](https://phalconphp.com) 正在使用Volt作為模板引擎運行,[Github](https://github.com/phalcon/website)
* [Phosphorum](https://forum.phalconphp.com),Phalcon的論壇,也使用Volt,[Github](https://github.com/phalcon/forum)
* [V?kuró](https://vokuro.phalconphp.com),是另一個使用Volt的示例應用程序,[Github](https://github.com/phalcon/vokuro)
- 常規
- Welcome
- 貢獻
- 生成回溯
- 測試重現
- 單元測試
- 入門
- 安裝
- Web服務器設置
- WAMP
- XAMPP
- 教程
- 基礎教程
- 教程:創建一個簡單的REST API
- 教程:V?kuró
- 提升性能
- 教程:INVO
- 開發環境
- Phalcon Compose (Docker)
- Nanobox
- Phalcon Box (Vagrant)
- 開發工具
- Phalcon開發者工具的安裝
- Phalcon開發者工具的使用
- 調試應用程序
- 核心
- MVC應用
- 微應用
- 創建命令行(CLI)應用程序
- 依賴注入與服務定位
- MVC架構
- 服務
- 使用緩存提高性能
- 讀取配置
- 上下文轉義
- 類加載器
- 使用命名空間
- 日志
- 隊列
- 數據庫
- 數據庫抽象層
- Phalcon查詢語言(PHQL)
- ODM(對象文檔映射器)
- 使用模型
- 模型行為
- ORM緩存
- 模型事件
- 模型元數據
- 模型關系
- 模型事務
- 驗證模型
- 數據庫遷移
- 分頁
- 前端
- Assets管理
- 閃存消息
- 表單
- 圖像
- 視圖助手(標簽)
- 使用視圖
- Volt:模板引擎
- 業務邏輯
- 訪問控制列表(ACL)
- 注解解析器
- 控制器
- 調度控制器
- 事件管理器
- 過濾與清理
- 路由
- 在session中存儲數據
- 生成URL和路徑
- 驗證
- HTTP
- Cookies管理
- 請求環境
- 返回響應
- 安全
- 加密/解密
- 安全
- 國際化
- 國際化
- 多語言支持