PhalconのテンプレートエンジンVolt (2)

今日は、PhalconのテンプレートエンジンVoltの2回目です。それでは、まずはじめにテストから調べてみます。

テスト

テストは、変数が有効な期待値を持っているかどうかをテストするために使用することができる。オペレータの “is” は、テストを実行するために使用されます。

{% set robots = ['1': 'Voltron', '2': 'Astro Boy', '3': 'Terminator', '4': 'C3PO'] %}
{% for position, name in robots %}
 {% if position is odd %}
 {{ name }}
 {% endif %}
 {% endfor %}

次の組み込みテストは、Voltで使用できます。

Test 説明
defined 変数が定義されているかどうかをチェック (isset)
empty 変数が空かどうかをチェック
even 数値が偶数かどうかをチェック
odd 数値が奇数かどうかをチェック
numeric 値が数値かどうかをチェック
scalar 値が配列かどうかをチェック (オブジェクトの配列を除く)
iterable 値が反復可能であるかどうかをチェック。”for”ステートメントによって横断することができる。
divisibleby 値が他の値で割りきれるかどうかをチェック
sameas 値が他の値と同じであるかどうかをチェック
type 値が指定した方であるかどうかをチェック

下記に例を表記します。

{% 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関数として機能し、パラメータと戻り値を受け取ることができます。

{%- 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) }}

マクロを呼び出すときに、パラメータは、名前で渡すことができます。

{%- 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') }}

マクロは値を返すことができます。

{%- macro my_input(name, class) %}
 {% return text_field(name, 'class': class) %}
 {%- endmacro %}
{# Call the macro #}
 {{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
また、オプションのパラメータを受け取ります。
{%- 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のテンプレートで、コンポーネントが提供するヘルパーを使用するように簡単です。

{{ 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 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ヘルパーを呼び出すには、そのメソッドのuncamelizedバージョンを呼び出す必要があります:

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::numberField number_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

 

ビルトイン関数

次の組み込み関数は、ボルトで使用できます。

Name Description
content 以前のレンダリング段階で作成したコンテンツが含まれています
get_content  ‘content’ と同じ
partial 動的現在のテンプレートで部分ビューをロードします
super 親ブロックの内容をレンダリング
time 同じ名前のPHP関数を呼び出します
date 同じ名前のPHP関数を呼び出します
dump PHP関数の ‘var_dump’ の呼び出し
version フレームワークの現在のバージョンを返します。
constant PHPの定数を読み出す
url ‘url’ のサービスを使用して、URLを生成します。

 

Viewの統合

また、Voltと統合されているphalcon\Mvc\Viewには、ビュー階層で使用するのと同様にパーシャルを含めることができます。

{{ 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>

パーシャルは、実行時に含まれている、ボルトはまた、「include」を提供します。、これは、ビューのコンテンツをコンパイルし、含まれていたビューの一部としてその内容を返します。

{# 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」は、Voltを使うとき、パフォーマンスを少し向上させるのに役立つ特別はビヘイビアを持ちます。あなたが拡張を指定するならば、テンプレートがコンパイルされるとき、ファイルと「include」が存在すれば、ボルトは、親テンプレートで、テンプレートの内容をインライン化することができます。テンプレートは、「include」が「with」で渡された変数がある場合は、インライン化されていません。

{# The contents of 'partials/footer.volt' is compiled and inlined #}
 <div id="footer">{% include "partials/footer.volt" %}</div>

テンプレートの継承

テンプレートの継承を使用すると、コードを再利用することができ、他のテンプレートで拡張することができるベースのテンプレートを作成することができます。ベーステンプレートは、子テンプレートで上書きすることができるブロックを定義します。我々は以下のベーステンプレートを持っているふりをしてみましょう:

{# 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 %}&copy; Copyright 2012, All rights reserved.{% endblock %}
 </div>
 </body>
</html>

他のテンプレートから、我々は、ブロックを交換するベーステンプレートを拡張できます。

{% 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 %}

(必要とされているもの以外)すべてのブロックが子テンプレートに置き換わる必要は、ありません。生成する最終出力は次のようになります。

<!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">
 &copy; Copyright 2012, All rights reserved.
 </div>
 </body>
</html>

多重継承

拡張テンプレートは、他のテンプレートを拡張することができます。次の例は、これを示しています。

{# 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 %}
「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()」関数の呼び出しに注意してください。その関数で、それは親ブロックの内容をレンダリングすることが可能です。

パーシャルで、「extends」に設定したパスは、現在のビューのディレクトリの下の相対パス(すなわちapp/views/)です。

デフォルトでは、パフォーマンス上の理由から、Voltは、プレーンなPHPに再コンパイルするときに、子テンプレートについて調べるだけです。ですので、compileAlways’ => trueオプションで、初期化することが推奨されています。これによって、テンプレートは親テンプレートの変化を考慮し、常にコンパイルされます。

自動エスケープモード

あなたはautoescapeモードを使用してブロック内に出力されたすべての変数の自動エスケープを有効にすることができます。

Manually escaped: {{ robot.name|e }}
{% autoescape true %}
 Autoescaped: {{ robot.name }}
 {% autoescape false %}
 No Autoescaped: {{ robot.name }}
 {% endautoescape %}
{% endautoescape %}

Voltエンジンのセットアップ

ボルトは、デフォルトの動作を変更するように構成することができます。以下の例では、それを行う方法について説明します。

<?php
use Phalcon\Mvc\View,
 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;
});

あなたがサービスとしてボルトを再利用したくない場合は、代わりにサービス名のエンジンを登録した無名関数を渡すことができます。

<?php
//Register Volt as template engine with an anonymous function
$di->set('view', function() {
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
 ".volt" => function($view, $di) {
 $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
//set some options here
return $volt;
 }
 ));
return $view;
});

次のオプションがボルトで使用できます。

オプション 説明 Default
compiledPath コンパイルされたPHPのテンプレートが配置される書き込み可能なパス ./
compiledExtension コンパイル済みのPHPファイルに追加の拡張 .php
compiledSeparator ボルトは、コンパイルされたディレクトリ内の単一のファイルを作成するために、このセパレーターで、「/」と「\」を置き換えます。 %%
stat Phalconがテンプレートとそのコンパイルされたパスの違いがあるかどうかを確認する必要があるかどうか true
compileAlways テンプレートがコンパイルする必要があるかどうか false
prefix コンパイルパスで、テンプレートパスに、接頭辞を付加する null

コンパイルパスは、この機能は、ビューのディレクトリ内のテンプレートへの相対パスを受け取り、開発者は、コンパイルパスを定義する完全な自由を望む場合、無名関数は、それを生成するために使用することができ、上記のオプションに応じて生成される。次の例では、動的にコンパイルパスを変更する方法を示します。

<?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の拡張

他のテンプレートエンジンとは異なり、ボルト自体は、コンパイルされたテンプレートを実行する必要はありません。テンプレートがコンパイルされたら、ボルトには依存性がありません。パフォーマンスの独立性では、ボルトはPHPのテンプレート用のコンパイラとして機能することを念頭に置いてください。

ボルトのコンパイラでは、既存のものに多くの機能、テストまたはフィルタの追加、それを拡張することができます。

Functions

関数は、通常のPHP関数として機能し、有効な文字列名は、関数名として必要とされます。関数は、2つのストラテジーを使用して、単純な文字列を返すか、無名関数を使用して追加することができます。常に選択したストラテジーは有効なPHP文字列式を返すことが必要です。

<?php
$volt = new \Phalcon\Mvc\View\Engine\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
$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
$compiler->addFunction('contains_text', function($resolvedArgs, $exprArgs) {
 if (function_exists('mb_stripos')) {
 return 'mb_stripos(' . $resolvedArgs . ')';
 } else {
 return 'stripos(' . $resolvedArgs . ')';
 }
});

組み込み関数は、その名前の関数を追加することオーバーライドすることができます:

<?php
//Replace built-in filter 'capitalize'
$compiler->addFilter('capitalize', 'lcfirst');

Extensions

extensionsを持つ開発者は、テンプレートエンジンを拡張し、特定の命令のコンパイルをオーバーライドし、表現やオペレータの動作を変更する、関数/フィルタ、などを追加するより多くの柔軟性を持っています。

extensionsは自身の方法としてボルトによってトリガイベントを実装するクラスです。

たとえば、以下のクラスは、ボルト内の任意の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コードを返す必要があります。イベントは、文字列が返されない場合、コンパイルは、エンジンが提供するデフォルトの動作を使用して行われます。

次のコンパイルイベントは、拡張機能で実装することができます:

Event/Method 説明
compileFunction テンプレート内の任意の関数呼び出しをコンパイルしようとする前にトリガ
compileFilter テンプレートで任意のフィルタ呼び出しをコンパイルしようとする前にトリガ
resolveExpression 任意の式をコンパイルしようとする前にトリガされます。これにより、開発者は演算子を上書きすることができます
compileStatement 任意の式をコンパイルしようとする前にトリガされます。これにより、開発者は任意のステートメントを上書きすることができます

ボルトの拡張機能は、コンパイル時にそれらを利用可能にするコンパイラに登録されなければなりません。

<?php
//Register the extension in the compiler
$compiler->addExtension(new PhpFunctionExtension());

View部品のキャッシュ

ボルトでは、それは簡単なキャッシュビューの断片です。このキャッシュは、PHPによってビューが表示されるたびに実行されてからブロックの内容ことを防止し、パフォーマンスが向上します。

{% cache "sidebar" %}
 <!-- generate this content is slow so we are going to cache it -->
{% endcache %}

特定の秒数を設定する:

{# cache the sidebar by 1 hour #}
{% cache "sidebar" 3600 %}
 <!-- generate this content is slow so we are going to cache it -->
{% endcache %}

任意の有効な式は​​、キャッシュキーとして使用することができます。

{% cache ("article-" ~ post.id) 3600 %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endcache %}

キャッシングはビューコンポーネントを介してphalcon\Cacheコンポーネントによって行われます。この統合は、“Caching View Fragments”セクションにどのように機能するかの詳細な情報です。

テンプレートにサービスの注入

サービスコンテナ(DI)は、ボルトのために利用可能な場合は、あなただけのテンプレートでサービスの名前にアクセスすることでサービスを使用することができます。

{# Inject the 'flash' service #}
<div id="messages">{{ flash.output() }}</div>
{# Inject the 'security' service #}
<input type="hidden" name="token" value="{{ security.getToken() }}">

スタンドアロン コンポーネント

スタンドアロンモードでボルトを使用すると、以下のようになります。

<?php
//Create a compiler
$compiler = new \Phalcon\Mvc\View\Engine\Volt\Compiler();
//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();

本日は、以上です。

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

トラックバック&コメント

この投稿のトラックバックURL:

コメントをどうぞ

このページの先頭へ