« 目次

Movable Type オブジェクト・リファレンス

MT::Template::Context

概要

use MT::Template::Context;
MT::Template::Context->add_tag( FooBar => sub {
    my($ctx, $args) = @_;
    my $foo = $ctx->stash('foo')
        or return $ctx->error("No foo in context");
    $foo->bar;
});

## In a template:
## <$MTFooBar$>

解説

MT::Template::Contextクラスは、Movable Type組み込みの全テンプレート・タグの実装を可能にするとともに、プラグインのパブリック・インターフェースを提供します。このドキュメントは、Movable Typeのプラグインを実装するために必要なパブリック・メソッド、およびプラグイン開発者が使用する可能性のあるメソッドを提供します。もちろんプラグインでは、Movable Typeのデータベースから読み込まれるその他のオブジェクトを使用することも可能です。この場合、対象となる各クラス(MT::Entryなど)の文書を参照してください。

利用方法

MT::Template::Context->add_tag($name, \&subroutine)

add_tagメソッドは、たとえば<$MTEntryTitle$>といった、シンプルな変数タグをシステムに登録します。$nameにはタグ名(MTプレフィクスを除いたもの)を指定し、\&subroutineには無名または名前つきサブルーチンへのリファレンスを指定します。\&subroutineは、戻り値としてエラー(エラー処理を参照のこと)または定義済みスカラー値を返すものでなければなりません(undefを返すとエラーと解釈されるので、空文字列を返すようにします)。

MT::Template::Context->add_tag(ServerUptime => sub { `uptime` });

として呼び出すことにより、テンプレート内で<$MTServerUptime$>タグが使用できるようになります。

サブルーチンへのリファレンスには、2つの引数が渡されます。テンプレート生成時に用いたMT::Template::Contextオブジェクトと、テンプレート中のタグによって渡される引数を格納したハッシュ配列へのリファレンスです。

<$MTFooBar baz="1" quux="2"$>

のような形で指定した場合、サブルーチンに渡される第2引数は、次のようなハッシュ配列となります。

{
    'quux' => 2,
    'bar' => 1
};
MT::Template::Context->add_container_tag($name, \&subroutine)

このメソッドは、テンプレートにコンテナ・タグを登録します。通常、コンテナ・タグは、ループや条件分岐を実現するために用いますが、実際にはループにのみadd_container_tagメソッドを使用し、条件処理にはadd_conditional_tagメソッドを用いるのが現実的です。というのはこのタグは多くのバックエンド処理を行ってくれるからです(大部分の条件タグのハンドラーは類似した構造になっています)。$nameにはタグ名(MTプレフィクスを除いたもの)を指定し、\&subroutineには無名または名前つきサブルーチンへのリファレンスを指定します。\&subroutineは、戻り値としてエラー(後述のエラー処理の項を参照してください)、または定義済みスカラー値を返すものでなければなりません(undefを返すとエラーと解釈されるので、空文字列を返すようにします)。

サブルーチンへのリファレンスには、2つの引数が渡されます。テンプレート生成時に用いたMT::Template::Contextオブジェクトと、テンプレート中のタグから渡される引数を格納するハッシュ配列へのリファレンスです。

コンテナ・タグは一般的にループを実現するために用います。このため、サブルーチン内では、何らかの要素リストに関してループさせるループ構造を用意し、コンテナ・タグの内側で、各要素に対する表示を行うようなテンプレートタグを用意することになります。こうした内側のテンプレートタグは、トークン・リストとしてコンパイルされているため、MT::Builderオブジェクトを用いるだけで、このトークン・リストをスカラー文字列に変換し、出力に追加することができます。トークンのリストは$ctx->stash('tokens')に格納され、MT::Builderオブジェクトは$ctx->stash('builder')に格納されています。

<MTLoop>
    The value of I is: <$MTLoopIValue$>
</MTLoop>

これらのタグを実装するためのコードは次のようなものになります。

MT::Template::Context->add_container_tag(Loop => sub {
    my $ctx = shift;
    my $res = '';
    my $builder = $ctx->stash('builder');
    my $tokens = $ctx->stash('tokens');
    for my $i (1..5) {
        $ctx->stash('i_value', $i);
        defined(my $out = $builder->build($ctx, $tokens))
        or return $ctx->error($builder->errstr);
        $res .= $out;
    }
    $res;
});

MT::Template::Context->add_tag(LoopIValue => sub {
    my $ctx = shift;
    $ctx->stash('i_value');
});

<$MTLoopIValue$>はシンプルな変数タグです。<MTLoop>はコンテナ・タグとして登録されており、1~5の数値についてループし、<MTLoop>~</MTLoop>間で各数値に対するトークンのリストを生成します。1回のループ実行ごとに、$builder->build呼び出しでエラー戻り値が返されていないかどうかをチェックしています。

表示結果は次のようになります。

The value of I is: 1
The value of I is: 2
The value of I is: 3
The value of I is: 4
The value of I is: 5
MT::Template::Context->add_conditional_tag($name, $condition)

このメソッドは、テンプレートに条件タグを登録します。技術的には、条件タグはコンテナ・タグですが、add_conditional_tagメソッドを使うことにより、条件タグの記述が非常に容易になります。$nameにはタグ名(MTプレフィクスを除く)を指定し、$conditionには、条件が満たされたときにtrueを返し、そうでないときにfalseを返すようなサブルーチンへのリファレンスを指定します。この条件が真の場合に、条件タグで囲まれたブロックとその内側のマークアップが実行され、表示されます。偽の場合にはブロック内部は無視されます。たとえば、以下のコードは2つの条件タグを登録するものです。

MT::Template::Context->add_conditional_tag(IfYes => sub { 1 });
MT::Template::Context->add_conditional_tag(IfNo => sub { 0 });

<MTIfYes>タグは、サブルーチンが常に1を返すため、ブロック内のコンテンツが常に表示されます。<MTIfNo>は、サブルーチンが常に0を返すため、ブロック内のコンテンツが常に非表示となります。

<MTIfYes>Yes, this appears.</MTIfYes>
<MTIfNo>No, this doesn't appear.</MTIfNo>

のように使った場合、常にYes, this appears.の部分のみが表示されることになります。

もう少し意味のある例をあげると、エントリコンテキスト内で、エントリにタイトルがある場合のみブロック内のコンテンツを表示するような<MTEntryIfTitle>タグを登録するには、次のようなコードを記述します。

MT::Template::Context->add_conditional_tag(EntryIfTitle => sub {
    my $e = $_[0]->stash('entry') or return;
    defined($e->title) && $e->title ne '';
});

このタグはテンプレート内では次のように使用します。

<MTEntries>
<MTEntryIfTitle>
    This entry has a title: <$MTEntryTitle$>
</MTEntryIfTitle>
</MTEntries>
MT::Template::Context->add_global_filter($name, \&subroutine)

このメソッドは、グローバルなタグ属性を登録します。Movable Typeマニュアルのテンプレート・タグセクションにあるグローバル・タグ・アトリビュートの項に、より詳細な情報が記載されています。

グローバル・タグ・アトリビュートは任意のタグ内で指定可能で、基本的にグローバル・フィルター(タグによる通常の出力をフィルターし、何らかの形で変更するために用いる)として機能します。たとえばグローバル・タグ・アトリビュートlower_caseは、

<$MTEntryTitle lower_case="1"$>

のように用いることで、すべてのエントリー・タイトルを小文字に変換することができます。

add_global_filterメソッドを用いることにより、独自のグローバル・フィルター定義することが可能です。$nameにはフィルター名(一貫性を保つため小文字で記述してください)を指定し、\&subroutineには、そのタグによる通常の出力を変換するために呼び出すサブルーチンへのリファレンスを指定します。\&subroutineには以下の3つの引数が渡されます。タグの標準的な出力(スカラー値)、属性値(上のlower_caseの例では1)、テンプレート生成時に用いたMT::Template::Contextオブジェクトです。次の例では、rot13という名前のフィルターを登録します。

MT::Template::Context->add_global_filter(rot13 => sub {
    (my $s = shift) =~ tr/a-zA-Z/n-za-mN-ZA-M/;
    $s;
});

このフィルターはテンプレート中で次のように用います。

<$MTEntryTitle rot13="1"$>

もう一つの例として、Movable Typeの組み込みフィルターであるtrim_toを、add_global_filterメソッドで実装するためには、次のようなコードを記述します。

MT::Template::Context->add_global_filter(trim_to => sub {
    my($str, $len, $ctx) = @_;
    $str = substr $str, 0, $len if $len < length($str);
    $str;
});

ここで、第2引数の$lenには、文字列$strを切り詰める文字数を指定します。

注意:同じ名前で複数のフィルターを登録した場合、呼び出しの優先順位は定義されていないので、特定の優先順位で呼び出しが行われることを期待することはできません。

$ctx->stash($key [, $value ])

このメソッドは、プラグイン中で、異なるタグの呼び出しの間でやり取りするデータを格納するシンプルなスタッシュの読み書きを行います。たとえば、上述の<MTLoop>タグの実装例に示したように、コンテナ・タグを実装する際に有用です。

$keyはスタッシュを識別するためのスカラー文字列でなければなりません。$valueを指定する場合、任意のスカラー値(文字列、数値、リファレンス、オブジェクトなど)が指定可能です。

$keyのみを指定してこのメソッドを呼び出すと、$keyというキーでスタッシュに格納されている値が返されます。$key$valueの両方を指定した場合、$keyのスタッシュの値を$valueに設定します。

エラー処理

プラグイン内のサブルーチンハンドラでエラーが生じた場合、次のように*$ctx*オブジェクトの*error*メソッドを呼び出してエラーを返す必要があります。

return $ctx->error("the error message");

特に、特定のコンテキスト内で呼び出すことを前提とするタグについては、このメソッドを用いることがよくあります。たとえば<$MTEntry*$>タグはすべて、コンテキスト中にエントリが存在することを前提としています。

my $entry = $ctx->stash('entry')
    or return $ctx->error("Tag called without an entry in context");

と記述することにより、エントリが存在しないコンテキストでの呼び出し時にエラーを返すようになっています。


Copyright © 2001-2006 Six Apart, Ltd. All Rights Reserved.