企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# Volt 模版引擎(Volt: Template Engine) # Volt 模版引擎(Volt: Template Engine) Volt 是一个用C为PHP编写的超快的并且对设计师友好的模板语言。Volt 提供一组辅助工具有助于你以一种更简单的的方式编写视图(Views)。同时,Volt与Phalcon的其他组件高度集成在一起,就像你在应用中单独使用Volt一样。 Volt is an ultra-fast and designer friendly templating language written in C for PHP. It provides you a set ofhelpers to write views in an easy way. Volt is highly integrated with other components of Phalcon,just as you can use it as a stand-alone component in your applications. ![](https://box.kancloud.cn/2015-12-30_5683411ee7ee6.jpg) Volt is inspired by [Jinja](http://jinja.pocoo.org/), originally created by [Armin Ronacher](https://github.com/mitsuhiko). Therefore many developers will be in familiarterritory using the same syntax they have been using with similar template engines. Volt’s syntax and featureshave been enhanced with more elements and of course with the performance that developers have beenaccustomed to while working with Phalcon. ### 简介(Introduction) Volt views are compiled to pure PHP code, so basically they save the effort of writing PHP code manually: Volt 视图被编译成纯PHP代码,所以基本上他们节省手工编写PHP代码的工作: ``` <pre class="calibre14">``` {# 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 %} ``` ``` ### 启用 Vlot(Activating Volt) As other template engines, you may register Volt in the view component, using a new extension orreusing the standard .phtml: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\View; // Registering Volt as template engine $di->set('view', function () { $view = new View(); $view->setViewsDir('../app/views/'); $view->registerEngines(array( ".volt" => 'Phalcon\Mvc\View\Engine\Volt' )); return $view; }); ``` ``` Use the standard ”.phtml” extension: ``` <pre class="calibre14">``` <?php $view->registerEngines(array( ".phtml" => 'Phalcon\Mvc\View\Engine\Volt' )); ``` ``` ### 基本用法(Basic Usage) A view consists of Volt code, PHP and HTML. A set of special delimiters is available to enter intoVolt mode. {% ... %} is used to execute statements such as for-loops or assign values and {{ ... }},prints the result of an expression to the template. Below is a minimal template that illustrates a few basics: ``` <pre class="calibre14">``` {# app/views/posts/show.phtml #} <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> ``` ``` Using Phalcon\\Mvc\\View you can pass variables from the controller to the [views.In](http://views.In) the above example, three variables were passed to the view: title, menu and post: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Controller; class PostsController extends Controller { public function showAction() { $post = Post::findFirst(); $this->view->title = $post->title; $this->view->post = $post; $this->view->menu = Menu::find(); $this->view->show_navigation = true; } } ``` ``` ### 变量(Variables) Object variables may have attributes which can be accessed using the syntax: foo.bar.If you are passing arrays, you have to use the square bracket syntax: foo\[‘bar'\] ``` <pre class="calibre14">``` {{ post.title }} {# for $post->title #} {{ post['title'] }} {# for $post['title'] #} ``` ``` ### 过滤器(Filters) Variables can be formatted or modified using filters. The pipe operator | is used to apply filters tovariables: ``` <pre class="calibre14">``` {{ post.title|e }} {{ post.content|striptags }} {{ name|capitalize|trim }} ``` ``` The following is the list of available built-in filters in Volt: FilterDescriptioneApplies Phalcon\\Escaper->escapeHtml to the valueescapeApplies Phalcon\\Escaper->escapeHtml to the valueescape\_cssApplies Phalcon\\Escaper->escapeCss to the valueescape\_jsApplies Phalcon\\Escaper->escapeJs to the valueescape\_attrApplies Phalcon\\Escaper->escapeHtmlAttr to the valuetrimApplies the [trim](http://php.net/manual/en/function.trim.php) PHP function to the value. Removing extra spacesleft\_trimApplies the [ltrim](http://php.net/manual/en/function.ltrim.php) PHP function to the value. Removing extra spacesright\_trimApplies the [rtrim](http://php.net/manual/en/function.rtrim.php) PHP function to the value. Removing extra spacesstriptagsApplies the [striptags](http://php.net/manual/en/function.striptags.php) PHP function to the value. Removing HTML tagsslashesApplies the [slashes](http://php.net/manual/en/function.slashes.php) PHP function to the value. Escaping valuesstripslashesApplies the [stripslashes](http://php.net/manual/en/function.stripslashes.php) PHP function to the value. Removing escaped quotescapitalizeCapitalizes a string by applying the [ucwords](http://php.net/manual/en/function.ucwords.php) PHP function to the valuelowerChange the case of a string to lowercaseupperChange the case of a string to uppercaselengthCounts the string length or how many items are in an array or objectnl2brChanges newlines \\n by line breaks ( ). Uses the PHP function [nl2br](http://php.net/manual/en/function.nl2br.php)sortSorts an array using the PHP function [asort](http://php.net/manual/en/function.asort.php)keysReturns the array keys using [array\_keys](http://php.net/manual/en/function.array-keys.php)joinJoins the array parts using a separator [join](http://php.net/manual/en/function.join.php)formatFormats a string using [sprintf](http://php.net/manual/en/function.sprintf.php).json\_encodeConverts a value into its [JSON](http://php.net/manual/en/function.json-encode.php) representationjson\_decodeConverts a value from its [JSON](http://php.net/manual/en/function.json-encode.php) representation to a PHP representationabsApplies the [abs](http://php.net/manual/en/function.abs.php) PHP function to a value.url\_encodeApplies the [urlencode](http://php.net/manual/en/function.urlencode.php) PHP function to the valuedefaultSets a default value in case that the evaluated expression is empty(is not set or evaluates to a falsy value)convert\_encodingConverts a string from one charset to anotherExamples: ``` <pre class="calibre14">``` {# 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 #} {% "a".."z"|join(",") %} {# format filter #} {% "My real name is %s"|format(name) %} {# json_encode filter #} {% 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: ``` <pre class="calibre14">``` {# 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: ``` <pre class="calibre14">``` <h1>Robots</h1> <ul> {% for robot in robots %} <li>{{ robot.name|e }}</li> {% endfor %} </ul> ``` ``` for-loops can also be nested: ``` <pre class="calibre14">``` <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: ``` <pre class="calibre14">``` {% 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: ``` <pre class="calibre14">``` {% 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: ``` <pre class="calibre14">``` <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: ``` <pre class="calibre14">``` <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: ``` <pre class="calibre14">``` {# skip the even robots #} {% for index, robot in robots %} {% if index is even %} {% continue %} {% endif %} ... {% endfor %} ``` ``` ``` <pre class="calibre14">``` {# 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: ``` <pre class="calibre14">``` <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: ``` <pre class="calibre14">``` <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: ``` <pre class="calibre14">``` {% 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 VariableDescriptionloop.indexThe current iteration of the loop. (1 indexed)loop.index0The current iteration of the loop. (0 indexed)loop.revindexThe number of iterations from the end of the loop (1 indexed)loop.revindex0The number of iterations from the end of the loop (0 indexed)loop.firstTrue if in the first iteration.loop.lastTrue if in the last iteration.loop.lengthThe number of items to iterate``` <pre class="calibre14">``` {% 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”: ``` <pre class="calibre14">``` {% set fruits = ['Apple', 'Banana', 'Orange'] %} {% set name = robot.name %} ``` ``` Multiple assignments are allowed in the same instruction: ``` <pre class="calibre14">``` {% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %} ``` ``` Additionally, you can use compound assignment operators: ``` <pre class="calibre14">``` {% set price += 100.00 %} {% set age *= 5 %} ``` ``` The following operators are available: OperatorDescription=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: ``` <pre class="calibre14">``` {{ (1 + 1) * 2 }} ``` ``` If an expression needs to be evaluated without be printed the ‘do' statement can be used: ``` <pre class="calibre14">``` {% do (1 + 1) * 2 %} ``` ``` ### 字面值(Literals) The following literals are supported: FilterDescription“this is a string”Text between double quotes or single quotes are handled as strings100.25Numbers with a decimal part are handled as doubles/floats100Numbers without a decimal part are handled as integersfalseConstant “false” is the boolean false valuetrueConstant “true” is the boolean true valuenullConstant “null” is the Null value### 数组(Arrays) Whether you're using PHP 5.3, 5.4 or 5.5, you can create arrays by enclosing a list of values in square brackets: ``` <pre class="calibre14">``` {# 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'] }} ``` ``` Curly braces also can be used to define arrays or hashes: ``` <pre class="calibre14">``` {% set myArray = {'Apple', 'Banana', 'Orange'} %} {% set myHash = {'first': 1, 'second': 4/2, 'third': '3'} %} ``` ``` ### 算术运算(Math) You may make calculations in templates using the following operators: OperatorDescription+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: OperatorDescription==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: OperatorDescriptionorReturn true if the left or right operand is evaluated as trueandReturn true if both left and right operands are evaluated as truenotNegates an expression( expr )Parenthesis groups expressions### 其他操作(Other Operators) Additional operators seen the following operators are available: OperatorDescription~Concatenates both operands {{ “hello ” ~ “world” }}..Creates a range {{ ‘a'..'z' }} {{ 1..10 }}isSame as == (equals), also performs testsinTo check if an expression is contained into other expressions if “a” in “abc”is notSame as != (not equals)‘a' ? ‘b' : ‘c'Ternary operator. The same as the PHP ternary operator++Increments a value–Decrements a valueThe following example shows how to use operators: ``` <pre class="calibre14">``` {% 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: ``` <pre class="calibre14">``` {% 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: TestDescriptiondefinedChecks if a variable is defined (isset)emptyChecks if a variable is emptyevenChecks if a numeric value is evenoddChecks if a numeric value is oddnumericChecks if value is numericscalarChecks if value is scalar (not an array or object)iterableChecks if a value is iterable. Can be traversed by a “for” statementdivisiblebyChecks if a value is divisible by other valuesameasChecks if a value is identical to other valuetypeChecks if a value is of the specified typeMore examples: ``` <pre class="calibre14">``` {% 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: ``` <pre class="calibre14">``` {%- macro related_bar(related_links) %} <ul> {%- for rellink 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: ``` <pre class="calibre14">``` {%- 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: ``` <pre class="calibre14">``` {%- 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: ``` <pre class="calibre14">``` {%- 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*](#), so it's easy to use the helpers provided by that component in a Volt template: ``` <pre class="calibre14">``` {{ 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: ``` <pre class="calibre14">``` <?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 helper, you only need to call an uncamelized version of the method: MethodVolt functionPhalcon\\Tag::linkTolink\_toPhalcon\\Tag::textFieldtext\_fieldPhalcon\\Tag::passwordFieldpassword\_fieldPhalcon\\Tag::hiddenFieldhidden\_fieldPhalcon\\Tag::fileFieldfile\_fieldPhalcon\\Tag::checkFieldcheck\_fieldPhalcon\\Tag::radioFieldradio\_fieldPhalcon\\Tag::dateFielddate\_fieldPhalcon\\Tag::emailFieldemail\_fieldPhalcon\\Tag::numberFieldnumber\_fieldPhalcon\\Tag::submitButtonsubmit\_buttonPhalcon\\Tag::selectStaticselect\_staticPhalcon\\Tag::selectselectPhalcon\\Tag::textAreatext\_areaPhalcon\\Tag::formformPhalcon\\Tag::endFormend\_formPhalcon\\Tag::getTitleget\_titlePhalcon\\Tag::stylesheetLinkstylesheet\_linkPhalcon\\Tag::javascriptIncludejavascript\_includePhalcon\\Tag::imageimagePhalcon\\Tag::friendlyTitlefriendly\_title### 函数(Functions) The following built-in functions are available in Volt: NameDescriptioncontentIncludes the content produced in a previous rendering stageget\_contentSame as ‘content'partialDynamically loads a partial view in the current templatesuperRender the contents of the parent blocktimeCalls the PHP function with the same namedateCalls the PHP function with the same namedumpCalls the PHP function ‘var\_dump'versionReturns the current version of the frameworkconstantReads a PHP constanturlGenerate a URL using the ‘url' service### 视图集成(View Integration) Also, Volt is integrated with [*Phalcon\\Mvc\\View*](#), you can play with the view hierarchy and include partials as well: ``` <pre class="calibre14">``` {{ 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 contentsas part of the view which was included: ``` <pre class="calibre14">``` {# 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 extensionwhen including the file and it exists when the template is compiled, Volt can inline the contents of the template in the parenttemplate where it's included. Templates aren't inlined if the ‘include' have variables passed with ‘with': ``` <pre class="calibre14">``` {# The contents of 'partials/footer.volt' is compiled and inlined #} <div id="footer">{% include "partials/footer.volt" %}</div> ``` ``` ### 模版的继承(Template Inheritance) With template inheritance you can create base templates that can be extended by others templates allowing to reuse code. A base templatedefine *blocks* than can be overridden by a child template. Let's pretend that we have the following base template: ``` <pre class="calibre14">``` {# templates/base.volt #} <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 %}&copy; Copyright 2015, All rights reserved.{% endblock %} </div> </body> </html> ``` ``` From other template we could extend the base template replacing the blocks: ``` <pre class="calibre14">``` {% 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 %} ``` ``` Not all blocks must be replaced at a child template, only those that are needed. The final output produced will be the following: ``` <pre class="calibre14">``` <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"> &copy; Copyright 2015, All rights reserved. </div> </body> </html> ``` ``` ### 多重继承(Multiple Inheritance) Extended templates can extend other templates. The following example illustrates this: ``` <pre class="calibre14">``` {# main.volt #} <html> <head> <title>Title</title> </head> <body> {% block content %}{% endblock %} </body> </html> ``` ``` Template “layout.volt” extends “main.volt” ``` <pre class="calibre14">``` {# layout.volt #} {% extends "main.volt" %} {% block content %} <h1>Table of contents</h1> {% endblock %} ``` ``` Finally a view that extends “layout.volt”: ``` <pre class="calibre14">``` {# index.volt #} {% extends "layout.volt" %} {% block content %} {{ super() }} <ul> <li>Some option</li> <li>Some other option</li> </ul> {% endblock %} ``` ``` Rendering “index.volt” produces: ``` <pre class="calibre14">``` <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> ``` ``` Note the call to the function “super()”. With that function it's possible to render the contents of the parent block. As partials, the path set to “extends” is a relative path under the current views directory (i.e. app/views/). > By default, and for performance reasons, Volt only checks for changes in the children templatesto know when to re-compile to plain PHP again, so it is recommended initialize Volt with the option‘compileAlways' => true. Thus, the templates are compiled always taking into account changes inthe parent templates. ### 自动编码模式(Autoescape mode) You can enable auto-escaping of all variables printed in a block using the autoescape mode: ``` <pre class="calibre14">``` Manually escaped: {{ robot.name|e }} {% autoescape true %} Autoescaped: {{ robot.name }} {% autoescape false %} No Autoescaped: {{ robot.name }} {% endautoescape %} {% endautoescape %} ``` ``` ### 配置 Volt 引擎(Setting up the Volt Engine) Volt can be configured to alter its default behavior, the following example explain how to do that: ``` <pre class="calibre14">``` <?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(array( "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(array( ".volt" => 'voltService' )); return $view; }); ``` ``` 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: ``` <pre class="calibre14">``` <?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(array( ".volt" => function ($view, $di) { $volt = new Volt($view, $di); // Set some options here return $volt; } )); return $view; }); ``` ``` The following options are available in Volt: OptionDescriptionDefaultcompiledPathA writable path where the compiled PHP templates will be placed./compiledExtensionAn additional extension appended to the compiled PHP file.phpcompiledSeparatorVolt replaces the directory separators / and \\ by this separator in order to create a single file in the compiled directory%%statWhether Phalcon must check if exists differences between the template file and its compiled pathtruecompileAlwaysTell Volt if the templates must be compiled in each request or only when they changefalseprefixAllows to prepend a prefix to the templates in the compilation pathnullThe 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 theviews directory. The following examples show how to change the compilation path dynamically: ``` <pre class="calibre14">``` <?php // Just append the .php extension to the template path // leaving the compiled templates in the same directory $volt->setOptions(array( 'compiledPath' => function ($templatePath) { return $templatePath . '.php'; } )); // Recursively create the same structure in another directory $volt->setOptions(array( 'compiledPath' => function ($templatePath) { $dirName = dirname($templatePath); if (!is_dir('cache/' . $dirName)) { mkdir('cache/' . $dirName); } return 'cache/' . $dirName . '/'. $templatePath . '.php'; } )); ``` ``` ### 扩展 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 anonymousfunction. Always is required that the chosen strategy returns a valid PHP string expression: ``` <pre class="calibre14">``` <?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 exactlyas were passed in the arguments: ``` <pre class="calibre14">``` <?php $compiler->addFunction('widget', function ($resolvedArgs, $exprArgs) { return 'MyLibrary\Widgets::get(' . $resolvedArgs . ')'; }); ``` ``` Treat the arguments independently and unresolved: ``` <pre class="calibre14">``` <?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: ``` <pre class="calibre14">``` <?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: ``` <pre class="calibre14">``` <?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 filtersis similar as seen with the functions: ``` <pre class="calibre14">``` <?php // This creates a filter 'hash' that uses the PHP function 'md5' $compiler->addFilter('hash', 'md5'); ``` ``` ``` <pre class="calibre14">``` <?php $compiler->addFilter('int', function ($resolvedArgs, $exprArgs) { return 'intval(' . $resolvedArgs . ')'; }); ``` ``` Built-in filters can be overridden adding a function with its name: ``` <pre class="calibre14">``` <?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 compilationof 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: ``` <pre class="calibre14">``` <?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 anytemplate. The purpose of the extension is to verify if a function to be compiled is a PHP function allowing to call itfrom the template. Events in extensions must return valid PHP code, this will be used as result of the compilationinstead of the one generated by Volt. If an event doesn't return an string the compilation is done using the defaultbehavior provided by the engine. The following compilation events are available to be implemented in extensions: Event/MethodDescriptioncompileFunctionTriggered before trying to compile any function call in a templatecompileFilterTriggered before trying to compile any filter call in a templateresolveExpressionTriggered before trying to compile any expression. This allows the developer to override operatorscompileStatementTriggered before trying to compile any expression. This allows the developer to override any statementVolt extensions must be in registered in the compiler making them available in compile time: ``` <pre class="calibre14">``` <?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 preventingthat the contents of a block from being executed by PHP each time the view is displayed: ``` <pre class="calibre14">``` {% cache "sidebar" %} <!-- generate this content is slow so we are going to cache it --> {% endcache %} ``` ``` Setting a specific number of seconds: ``` <pre class="calibre14">``` {# 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: ``` <pre class="calibre14">``` {% cache ("article-" ~ post.id) 3600 %} <h1>{{ post.title }}</h1> <p>{{ post.content }}</p> {% endcache %} ``` ``` The caching is done by the [*Phalcon\\Cache*](#) component via the view component.Learn more about how this integration works in the section [*“Caching View Fragments”*](#). ### 注入服务到模版(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: ``` <pre class="calibre14">``` {# 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: ``` <pre class="calibre14">``` <?php Phalcon\Mvc\View\Engine\Volt\Compiler as VoltCompiler; // Create a compiler $compiler = new VoltCompiler(); // Optionally add some options $compiler->setOptions(array( // ... )); // 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, \[[Github](https://github.com/phalcon/album-o-rama)\] - [Our website](http://phalconphp.com) is running using Volt as template engine, \[[Github](https://github.com/phalcon/website)\] - [Phosphorum](http://forum.phalconphp.com), the Phalcon's forum, also uses Volt, \[[Github](https://github.com/phalcon/forum)\] - [Vkuró](http://vokuro.phalconphp.com), is another sample application that use Volt, \[[Github](https://github.com/phalcon/vokuro)\] | - [索引](# "总目录") - [下一页](# "MVC 应用(MVC Applications)") | - [上一页](# "资源文件管理(Assets Management)") |