# Volt 模版引擎(Volt: Template Engine)
Volt 是一個用C為PHP編寫的超快的并且對設計師友好的模板語言。Volt 提供一組輔助工具有助于你以一種更簡單的的方式編寫視圖(Views)。 同時,Volt與Phalcon的其他組件高度集成在一起,就像你在應用中單獨使用Volt一樣。

Volt is inspired by[Jinja](http://jinja.pocoo.org/), originally created by[Armin Ronacher](https://github.com/mitsuhiko). Therefore many developers will be in familiar territory using the same syntax they have been using with similar template engines. Volt’s syntax and features have been enhanced with more elements and of course with the performance that developers have been accustomed to while working with Phalcon.
## 簡介(Introduction)
Volt 視圖被編譯成純PHP代碼,所以基本上他們節省手工編寫PHP代碼的工作:
~~~
{# 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(Activating Volt)
和其他模板引擎一樣,你需要將Volt模板注冊到視圖組件中,并設置模板文件通用后綴名,或者直接使用標準的后綴名”.phtml”才能正常使用:
~~~
<?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
$view->registerEngines(
[
".phtml" => "voltService",
]
);
~~~
You don’t have to specify the Volt Service in the DI; you can also use the Volt engine with the default settings:
~~~
<?php
$view->registerEngines(
[
".volt" => "Phalcon\\Mvc\\View\\Engine\\Volt",
]
);
~~~
If you do not want to reuse Volt as a service, you can pass an anonymous function to register the engine instead of a service name:
~~~
<?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 \Phalcon\Mvc\View();
$view->setViewsDir("../app/views/");
$view->registerEngines(
[
".volt" => function ($view, $di) {
$volt = new Volt($view, $di);
// Set some options here
return $volt;
}
]
);
return $view;
}
);
~~~
The following options are available in Volt:
| Option | Description | Default |
| --- | --- | --- |
| `compiledPath` | A writable path where the compiled PHP templates will be placed | ./ |
| `compiledExtension` | An additional extension appended to the compiled PHP file | .php |
| `compiledSeparator` | Volt replaces the directory separators / and \\ by this separator in order to create a single file in the compiled directory | %% |
| `stat` | Whether Phalcon must check if exists differences between the template file and its compiled path | true |
| `compileAlways` | Tell Volt if the templates must be compiled in each request or only when they change | false |
| `prefix` | Allows to prepend a prefix to the templates in the compilation path | null |
| `autoescape` | Enables globally autoescape of HTML | false |
The compilation path is generated according to the above options, if the developer wants total freedom defining the compilation path, an anonymous function can be used to generate it, this function receives the relative path to the template in the views directory. The following examples show how to change the compilation path dynamically:
~~~
<?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);
}
return "cache/" . $dirName . "/". $templatePath . ".php";
}
]
);
~~~
## 基本用法(Basic Usage)
視圖通常由Volt模板代碼和HTML代碼生成,甚至也含有PHP代碼。Volt模板中有一些特殊分隔符的用法:`{%...%}`用于執行流程控制語句如if判斷、for循環及賦值處理等等,`{{...}}`用于在模板中輸出表達式的執行結果。
下面例子介紹了一些基礎用法:
~~~
{# 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](http://docs.iphalcon.cn/api/Phalcon_Mvc_View.html)實例可以從控制器中把變量傳遞給視圖。 在下面的示例中,有四個變量傳遞給了視圖:`show_navigation`,`menu`,`title`and`post`:
~~~
<?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);
}
}
~~~
## 變量(Variables)
對象變量可能有一些屬性值,可以使用`foo.bar`的方式來訪問。如果傳遞的是一個數組變量,則必須使用`foo['bar']`的方式來訪問。
~~~
{{ post.title }} {# for $post->title #}
{{ post['title'] }} {# for $post['title'] #}
~~~
## 過濾器(Filters)
模板中的變量可以通過過濾器進行格式化。操作符`|`適用于對變量進行格式化:
~~~
{{ post.title|e }}
{{ post.content|striptags }}
{{ name|capitalize|trim }}
~~~
以下是Volt模板內置的過濾器列表:
Examples:
~~~
{# 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') }}
~~~
## 注釋(Comments)
Comments may also be added to a template using the`{#...#}`delimiters. All text inside them is just ignored in the final output:
~~~
{# note: this is a comment
{% set price = 100; %}
#}
~~~
## 流程控制列表(List of Control Structures)
Volt provides a set of basic but powerful control structures for use in templates:
### 循環語句 For
Loop over each item in a sequence. The following example shows how to traverse a set of “robots” and print his/her name:
~~~
<h1>Robots</h1>
<ul>
{% for robot in robots %}
<li>
{{ robot.name|e }}
</li>
{% endfor %}
</ul>
~~~
for-loops can also be nested:
~~~
<h1>Robots</h1>
{% for robot in robots %}
{% for part in robot.parts %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% endfor %}
{% endfor %}
~~~
You can get the element “keys” as in the PHP counterpart using the following syntax:
~~~
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for name, value in numbers %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
~~~
An “if” evaluation can be optionally set:
~~~
{% 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 %}
~~~
If an ‘else’ is defined inside the ‘for’, it will be executed if the expression in the iterator result in zero iterations:
~~~
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% else %}
There are no robots to show
{% endfor %}
~~~
Alternative syntax:
~~~
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% elsefor %}
There are no robots to show
{% endfor %}
~~~
### 循環控制(Loop Controls)
The ‘break’ and ‘continue’ statements can be used to exit from a loop or force an iteration in the current block:
~~~
{# skip the even robots #}
{% for index, robot in robots %}
{% if index is even %}
{% continue %}
{% endif %}
...
{% endfor %}
~~~
~~~
{# exit the foreach on the first even robot #}
{% for index, robot in robots %}
{% if index is even %}
{% break %}
{% endif %}
...
{% endfor %}
~~~
### 條件判斷語句 If
As PHP, an “if” statement checks if an expression is evaluated as true or false:
~~~
<h1>Cyborg Robots</h1>
<ul>
{% for robot in robots %}
{% if robot.type === "cyborg" %}
<li>{{ robot.name|e }}</li>
{% endif %}
{% endfor %}
</ul>
~~~
The else clause is also supported:
~~~
<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>
~~~
The ‘elseif’ control flow structure can be used together with if to emulate a ‘switch’ block:
~~~
{% if robot.type === "cyborg" %}
Robot is a cyborg
{% elseif robot.type === "virtual" %}
Robot is virtual
{% elseif robot.type === "mechanical" %}
Robot is mechanical
{% endif %}
~~~
### 循環上下文(Loop Context)
A special variable is available inside ‘for’ loops providing you information about
| Variable | Description |
| --- | --- |
| `loop.index` | The current iteration of the loop. (1 indexed) |
| `loop.index0` | The current iteration of the loop. (0 indexed) |
| `loop.revindex` | The number of iterations from the end of the loop (1 indexed) |
| `loop.revindex0` | The number of iterations from the end of the loop (0 indexed) |
| `loop.first` | True if in the first iteration. |
| `loop.last` | True if in the last iteration. |
| `loop.length` | The number of items to iterate |
~~~
{% 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 %}
~~~
## 賦值(Assignments)
Variables may be changed in a template using the instruction “set”:
~~~
{% set fruits = ['Apple', 'Banana', 'Orange'] %}
{% set name = robot.name %}
~~~
Multiple assignments are allowed in the same instruction:
~~~
{% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %}
~~~
Additionally, you can use compound assignment operators:
~~~
{% set price += 100.00 %}
{% set age *= 5 %}
~~~
The following operators are available:
| Operator | Description |
| --- | --- |
| \= | Standard Assignment |
| += | Addition assignment |
| \-= | Subtraction assignment |
| \*= | Multiplication assignment |
| /= | Division assignment |
## 表達式(Expressions)
Volt provides a basic set of expression support, including literals and common operators.
A expression can be evaluated and printed using the ‘{{‘ and ‘}}’ delimiters:
~~~
{{ (1 + 1) * 2 }}
~~~
If an expression needs to be evaluated without be printed the ‘do’ statement can be used:
~~~
{% do (1 + 1) * 2 %}
~~~
### 字面值(Literals)
The following literals are supported:
| Filter | Description |
| --- | --- |
| “this is a string” | Text between double quotes or single quotes are handled as strings |
| 100.25 | Numbers with a decimal part are handled as doubles/floats |
| 100 | Numbers without a decimal part are handled as integers |
| false | Constant “false” is the boolean false value |
| true | Constant “true” is the boolean true value |
| null | Constant “null” is the Null value |
### 數組(Arrays)
Whether you’re using PHP 5.3 or >= 5.4 you can create arrays by enclosing a list of values in square brackets:
~~~
{# 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'] }}
~~~
花括號也能用來定義數組或關聯數組:
~~~
{% set myArray = {'Apple', 'Banana', 'Orange'} %}
{% set myHash = {'first': 1, 'second': 4/2, 'third': '3'} %}
~~~
### 算術運算(Math)
你可以在模板里面使用下列操作符來進行算術運算:
| Operator | Description |
| --- | --- |
| `+` | Perform an adding operation.`{{2+3}}`returns 5 |
| `-` | Perform a substraction operation`{{2-3}}`returns -1 |
| `*` | Perform a multiplication operation`{{2*3}}`returns 6 |
| `/` | Perform a division operation`{{10/2}}`returns 5 |
| `%` | Calculate the remainder of an integer division`{{10%3}}`returns 1 |
### 比較運算(Comparisons)
The following comparison operators are available:
| Operator | Description |
| --- | --- |
| `==` | Check whether both operands are equal |
| `!=` | Check whether both operands aren’t equal |
| `<>` | Check whether both operands aren’t equal |
| `>` | Check whether left operand is greater than right operand |
| `<` | Check whether left operand is less than right operand |
| `<=` | Check whether left operand is less or equal than right operand |
| `>=` | Check whether left operand is greater or equal than right operand |
| `===` | Check whether both operands are identical |
| `!==` | Check whether both operands aren’t identical |
### 邏輯運算(Logic)
Logic operators are useful in the “if” expression evaluation to combine multiple tests:
| Operator | Description |
| --- | --- |
| `or` | Return true if the left or right operand is evaluated as true |
| `and` | Return true if both left and right operands are evaluated as true |
| `not` | Negates an expression |
| `(expr)` | Parenthesis groups expressions |
### 其他操作(Other Operators)
Additional operators seen the following operators are available:
| Operator | Description |
| --- | --- |
| `~` | Concatenates both operands`{{"hello"~"world"}}` |
| `|` | Applies a filter in the right operand to the left`{{"hello"|uppercase}}` |
| `..` | Creates a range`{{'a'..'z'}}``{{1..10}}` |
| `is` | Same as == (equals), also performs tests |
| `in` | To check if an expression is contained into other expressions`if"a"in"abc"` |
| `isnot` | Same as != (not equals) |
| `'a'?'b':'c'` | Ternary operator. The same as the PHP ternary operator |
| `++` | Increments a value |
| `--` | Decrements a value |
下面的示例顯示了如何使用操作符:
~~~
{% set robots = ['Voltron', 'Astro Boy', 'Terminator', 'C3PO'] %}
{% for index in 0..robots|length %}
{% if robots[index] is defined %}
{{ "Name: " ~ robots[index] }}
{% endif %}
{% endfor %}
~~~
## 測試運算(Tests)
Tests can be used to test if a variable has a valid expected value. The operator “is” is used to perform the tests:
~~~
{% set robots = ['1': 'Voltron', '2': 'Astro Boy', '3': 'Terminator', '4': 'C3PO'] %}
{% for position, name in robots %}
{% if position is odd %}
{{ name }}
{% endif %}
{% endfor %}
~~~
The following built-in tests are available in Volt:
| Test | Description |
| --- | --- |
| `defined` | Checks if a variable is defined (`isset()`) |
| `empty` | Checks if a variable is empty |
| `even` | Checks if a numeric value is even |
| `odd` | Checks if a numeric value is odd |
| `numeric` | Checks if value is numeric |
| `scalar` | Checks if value is scalar (not an array or object) |
| `iterable` | Checks if a value is iterable. Can be traversed by a “for” statement |
| `divisibleby` | Checks if a value is divisible by other value |
| `sameas` | Checks if a value is identical to other value |
| `type` | Checks if a value is of the specified type |
More examples:
~~~
{% 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 %}
~~~
## 宏定義(Macros)
Macros can be used to reuse logic in a template, they act as PHP functions, can receive parameters and return values:
~~~
{# 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) }}
~~~
When calling macros, parameters can be passed by name:
~~~
{%- 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') }}
~~~
Macros can return values:
~~~
{%- macro my_input(name, class) %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
~~~
And receive optional parameters:
~~~
{%- 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>' }}
~~~
## 使用標簽助手(Using Tag Helpers)
Volt is highly integrated with[Phalcon\\Tag](http://docs.iphalcon.cn/reference/tags.html), so it’s easy to use the helpers provided by that component in a Volt template:
~~~
{{ 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() }}
~~~
The following PHP is generated:
~~~
<?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() }}
~~~
To call a[Phalcon\\Tag](http://docs.iphalcon.cn/api/Phalcon_Tag.html)helper, you only need to call an uncamelized version of the method:
| Method | Volt function |
| --- | --- |
| `Phalcon\Tag::linkTo` | `link_to` |
| `Phalcon\Tag::textField` | `text_field` |
| `Phalcon\Tag::passwordField` | `password_field` |
| `Phalcon\Tag::hiddenField` | `hidden_field` |
| `Phalcon\Tag::fileField` | `file_field` |
| `Phalcon\Tag::checkField` | `check_field` |
| `Phalcon\Tag::radioField` | `radio_field` |
| `Phalcon\Tag::dateField` | `date_field` |
| `Phalcon\Tag::emailField` | `email_field` |
| `Phalcon\Tag::numericField` | `numeric_field` |
| `Phalcon\Tag::submitButton` | `submit_button` |
| `Phalcon\Tag::selectStatic` | `select_static` |
| `Phalcon\Tag::select` | `select` |
| `Phalcon\Tag::textArea` | `text_area` |
| `Phalcon\Tag::form` | `form` |
| `Phalcon\Tag::endForm` | `end_form` |
| `Phalcon\Tag::getTitle` | `get_title` |
| `Phalcon\Tag::stylesheetLink` | `stylesheet_link` |
| `Phalcon\Tag::javascriptInclude` | `javascript_include` |
| `Phalcon\Tag::image` | `image` |
| `Phalcon\Tag::friendlyTitle` | `friendly_title` |
## 函數(Functions)
The following built-in functions are available in Volt:
| Name | Description |
| --- | --- |
| `content` | Includes the content produced in a previous rendering stage |
| `get_content` | Same as`content` |
| `partial` | Dynamically loads a partial view in the current template |
| `super` | Render the contents of the parent block |
| `time` | Calls the PHP function with the same name |
| `date` | Calls the PHP function with the same name |
| `dump` | Calls the PHP function`var_dump()` |
| `version` | Returns the current version of the framework |
| `constant` | Reads a PHP constant |
| `url` | Generate a URL using the ‘url’ service |
## 視圖集成(View Integration)
Also, Volt is integrated with[Phalcon\\Mvc\\View](http://docs.iphalcon.cn/reference/views.html), you can play with the view hierarchy and include partials as well:
~~~
{{ 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>
~~~
A partial is included in runtime, Volt also provides “include”, this compiles the content of a view and returns its contents as part of the view which was included:
~~~
{# 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’ has a special behavior that will help us improve performance a bit when using Volt, if you specify the extension when including the file and it exists when the template is compiled, Volt can inline the contents of the template in the parent template where it’s included. Templates aren’t inlined if the ‘include’ have variables passed with ‘with’:
~~~
{# The contents of 'partials/footer.volt' is compiled and inlined #}
<div id="footer">
{% include "partials/footer.volt" %}
</div>
~~~
### Partial vs Include
Keep the following points in mind when choosing to use the “partial” function or “include”:
* ‘Partial’ 既可以引入Volt模板,也可以引入其他模板引擎的模板
* ‘Partial’ 在引入模板的時候,可以傳遞表達式(如變量)
* ‘Partial’ 更適合引入經常有變動的模板
* ‘Include’ 是引入編譯后的模板內容,以提升性能
* ‘Include’ 只能引入Volt模板
* ‘Include’ 在編譯時須引入現有的模板
## 模版的繼承(Template Inheritance)
你可以創建基礎模板,供其他模板繼承,達到代碼復用的目的。在基礎模板中使用*block*定義代碼塊,則子模板可以實現重寫功能。 我們假設有一個這樣的基礎模板:
~~~
{# 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>
~~~
其他的模板繼承了基礎模板后,會重寫基礎模板中的*block*代碼塊:
~~~
{% 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 %}
~~~
在子模板中并不需要全部重寫基礎模板中的*block*塊,按需要重寫部分即可。最終輸出如下示例:
~~~
<!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>
~~~
### 多重繼承(Multiple Inheritance)
子模板也可以被其他模板繼承,下面的示例演示了模板的多重繼承:
~~~
{# main.volt #}
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
~~~
“layout.volt” 繼承 “main.volt”
~~~
{# layout.volt #}
{% extends "main.volt" %}
{% block content %}
<h1>Table of contents</h1>
{% endblock %}
~~~
“index.volt” 又繼承了 “layout.volt”:
~~~
{# index.volt #}
{% extends "layout.volt" %}
{% block content %}
{{ super() }}
<ul>
<li>Some option</li>
<li>Some other option</li>
</ul>
{% endblock %}
~~~
渲染 “index.volt” 后輸出:
~~~
<!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()`方法,此方法用于獲取父模板中渲染的內容。
As partials, the path set to “extends” is a relative path under the current views directory (i.e. app/views/).
> 通常情況下,出于性能方面的考慮,Volt模板引擎在重新編譯模板時只會檢查子模板中的內容變更。 所以建議設置Volt模板引擎的選項參數`'compileAlways'=>true`。這樣模板會實時編譯,并檢查父模板中的內容變更。
## 自動編碼模式(Autoescape mode)
You can enable auto-escaping of all variables printed in a block using the autoescape mode:
~~~
Manually escaped: {{ robot.name|e }}
{% autoescape true %}
Autoescaped: {{ robot.name }}
{% autoescape false %}
No Autoescaped: {{ robot.name }}
{% endautoescape %}
{% endautoescape %}
~~~
## 擴展 Volt(Extending Volt)
Unlike other template engines, Volt itself is not required to run the compiled templates. Once the templates are compiled there is no dependence on Volt. With performance independence in mind, Volt only acts as a compiler for PHP templates.
The Volt compiler allow you to extend it adding more functions, tests or filters to the existing ones.
### 函數(Functions)
Functions act as normal PHP functions, a valid string name is required as function name. Functions can be added using two strategies, returning a simple string or using an anonymous function. Always is required that the chosen strategy returns a valid PHP string expression:
~~~
<?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");
~~~
Register the function with an anonymous function. This case we use`$resolvedArgs`to pass the arguments exactly as were passed in the arguments:
~~~
<?php
$compiler->addFunction(
"widget",
function ($resolvedArgs, $exprArgs) {
return "MyLibrary\\Widgets::get(" . $resolvedArgs . ")";
}
);
~~~
Treat the arguments independently and unresolved:
~~~
<?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 . ")";
}
);
~~~
Generate the code based on some function availability:
~~~
<?php
$compiler->addFunction(
"contains_text",
function ($resolvedArgs, $exprArgs) {
if (function_exists("mb_stripos")) {
return "mb_stripos(" . $resolvedArgs . ")";
} else {
return "stripos(" . $resolvedArgs . ")";
}
}
);
~~~
Built-in functions can be overridden adding a function with its name:
~~~
<?php
// Replace built-in function dump
$compiler->addFunction("dump", "print_r");
~~~
### 過濾器(Filters)
A filter has the following form in a template: leftExpr|name(optional-args). Adding new filters is similar as seen with the functions:
~~~
<?php
// This creates a filter 'hash' that uses the PHP function 'md5'
$compiler->addFilter("hash", "md5");
~~~
~~~
<?php
$compiler->addFilter(
"int",
function ($resolvedArgs, $exprArgs) {
return "intval(" . $resolvedArgs . ")";
}
);
~~~
Built-in filters can be overridden adding a function with its name:
~~~
<?php
// Replace built-in filter 'capitalize'
$compiler->addFilter("capitalize", "lcfirst");
~~~
### 擴展(Extensions)
With extensions the developer has more flexibility to extend the template engine, and override the compilation of a specific instruction, change the behavior of an expression or operator, add functions/filters, and more.
An extension is a class that implements the events triggered by Volt as a method of itself.
For example, the class below allows to use any PHP function in Volt:
~~~
<?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 . ")";
}
}
}
~~~
The above class implements the method ‘compileFunction’ which is invoked before any attempt to compile a function call in any template. The purpose of the extension is to verify if a function to be compiled is a PHP function allowing to call it from the template. Events in extensions must return valid PHP code, this will be used as result of the compilation instead of the one generated by Volt. If an event doesn’t return an string the compilation is done using the default behavior provided by the engine.
The following compilation events are available to be implemented in extensions:
| Event/Method | Description |
| --- | --- |
| `compileFunction` | Triggered before trying to compile any function call in a template |
| `compileFilter` | Triggered before trying to compile any filter call in a template |
| `resolveExpression` | Triggered before trying to compile any expression. This allows the developer to override operators |
| `compileStatement` | Triggered before trying to compile any expression. This allows the developer to override any statement |
Volt extensions must be in registered in the compiler making them available in compile time:
~~~
<?php
// Register the extension in the compiler
$compiler->addExtension(
new PhpFunctionExtension()
);
~~~
## 緩存視圖片段(Caching view fragments)
With Volt it’s easy cache view fragments. This caching improves performance preventing that the contents of a block from being executed by PHP each time the view is displayed:
~~~
{% cache "sidebar" %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
~~~
Setting a specific number of seconds:
~~~
{# cache the sidebar by 1 hour #}
{% cache "sidebar" 3600 %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
~~~
Any valid expression can be used as cache key:
~~~
{% cache ("article-" ~ post.id) 3600 %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endcache %}
~~~
The caching is done by the[Phalcon\\Cache](http://docs.iphalcon.cn/reference/cache.html)component via the view component. Learn more about how this integration works in the section[“Caching View Fragments”](http://docs.iphalcon.cn/reference/views.html).
## 注入服務到模版(Inject Services into a Template)
If a service container (DI) is available for Volt, you can use the services by only accessing the name of the service in the template:
~~~
{# Inject the 'flash' service #}
<div id="messages">{{ flash.output() }}</div>
{# Inject the 'security' service #}
<input type="hidden" name="token" value="{{ security.getToken() }}">
~~~
## 獨立的組件(Stand-alone component)
Using Volt in a stand-alone mode can be demonstrated below:
~~~
<?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();
~~~
## 外部資源(External Resources)
* A bundle for Sublime/Textmate is available[here](https://github.com/phalcon/volt-sublime-textmate)
* [Album-O-Rama](http://album-o-rama.phalconphp.com/)is a sample application using Volt as template engine, \[[Album-O-Rama on Github](https://github.com/phalcon/album-o-rama)\]
* [Our website](http://phalconphp.com/)is running using Volt as template engine, \[[Our website on Github](https://github.com/phalcon/website)\]
* [Phosphorum](http://forum.phalconphp.com/), the Phalcon’s forum, also uses Volt, \[[Phosphorum on Github](https://github.com/phalcon/forum)\]
* [V?kuró](http://vokuro.phalconphp.com/), is another sample application that use Volt, \[[V?kuró on Github](https://github.com/phalcon/vokuro)\]
- 簡介
- 安裝
- 安裝(installlation)
- XAMPP下的安裝
- WAMP下安裝
- Nginx安裝說明
- Apache安裝說明
- Cherokee 安裝說明
- 使用 PHP 內置 web 服務器
- Phalcon 開發工具
- Linux 系統下使用 Phalcon 開發工具
- Mac OS X 系統下使用 Phalcon 開發工具
- Windows 系統下使用 Phalcon 開發工具
- 教程
- 教程 1:讓我們通過例子來學習
- 教程 2:INVO簡介
- 教程 3: 保護INVO
- 教程4: 使用CRUD
- 教程5: 定制INVO
- 教程 6: V?kuró
- 教程 7:創建簡單的 REST API
- 組件
- 依賴注入與服務定位器
- MVC架構
- 使用控制器
- 使用模型
- 模型關系
- 事件與事件管理器
- Behaviors
- 模型元數據
- 事務管理
- 驗證數據完整性
- Workingwith Models
- Phalcon查詢語言
- 緩存對象關系映射
- 對象文檔映射 ODM
- 使用視圖
- 視圖助手
- 資源文件管理
- Volt 模版引擎
- MVC 應用
- 路由
- 調度控制器
- Micro Applications
- 使用命名空間
- 事件管理器
- Request Environmen
- 返回響應
- Cookie 管理
- 生成 URL 和 路徑
- 閃存消息
- 使用 Session 存儲數據
- 過濾與清理
- 上下文編碼
- 驗證Validation
- 表單_Forms
- 讀取配置
- 分頁 Pagination
- 使用緩存提高性能
- 安全
- 加密與解密 Encryption/Decryption
- 訪問控制列表
- 多語言支持
- 類加載器 Class Autoloader
- 日志記錄_Logging
- 注釋解析器 Annotations Parser
- 命令行應用 Command Line Applications
- Images
- 隊列 Queueing
- 數據庫抽象層
- 國際化
- 數據庫遷移
- 調試應用程序
- 單元測試
- 進階技巧與延伸閱讀
- 提高性能:下一步該做什么?
- Dependency Injection Explained
- Understanding How Phalcon Applications Work
- Api
- Abstract class Phalcon\Acl