Movable Type/第6回MTプラグイン勉強会 - グローバルフィルターを使ったエントリー内変数の再構築時置換、再構築呼び出し http://www.ark-web.jp/sandbox/wiki/333.html
Movable Type/第6回MTプラグイン勉強会 - グローバルフィルターを使ったエントリー内変数の再構築時置換、再構築呼び出し
第6回はグローバルフィルターを使ってエントリー内に独自に定義した変数を再構築時に置換する方法、また、再構築をプラグインから呼び出す方法をとりあげます。A-Formではエントリー内に埋め込んだ変数(<!--aform001-->など)を再構築時に定義したフォームに置き換えるのに使っています。
動画(Ustream) †
勉強会の模様をアップしました。
Live .TV show provided by UstreamUstreamのチャンネルはこちら。
http://www.ustream.tv/channel/mt%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E5%8B%89%E5%BC%B7%E4%BC%9A
ご感想・ご質問など †
ご感想、ご質問などあればお気軽にどうぞ。頂けるととても励みになります。
勉強会で解説したプログラムコードのダウンロード †
単に対象のファンクションタグの出力を‘’で囲むだけのプラグインです。
グローバルフィルターの実装例としてご参考ください。
ネタ †
日時 †
- 2008/06/27(金) 10:30〜11:00
グローバルフィルターを使って再構築時にエントリー内の独自変数を置換する †
グローバルフィルターを使って再構築時にエントリー内の独自変数を置換します。グローバルフィルターを使うため、エントリーの保存の際にも定義した置換処理が走ります。
グローバルフィルター作成の基礎的なこと †
グローバルフィルターはプラグインの一種(または一機能)として実装します。フィルタープラグインの一種です。(Six Apart - 技術情報提供ブログ: プラグイン開発のためのファーストステップ)
グローバルフィルタープラグインの作成方法はSix Apart - 技術情報提供ブログ: フィルター プラグインの開発に詳説されています。ここでは、技術情報提供ブログの方法とは少し変えてMT::Pluginのregistryメソッドを利用して、グローバルフィルターを定義する方法をとりあげます。
MT::Plugin->registryを使ったグローバルフィルターの定義は次のようになります。
sub init_registry { my $plugin = shift; $plugin->registry({ tags => { modifier => { 属性名 => ハンドラ(関数リファレンス), }, }, }); }
例えば、MTテンプレートのファンクションタグ(何らかの文字列を出力するタグ)に属性quote="1"を指定すると出力する文字列全体を‘と’で囲むフィルターを作る場合、
属性名 quote 、ハンドラを _quote_strとするとregistryは
sub init_registry { my $plugin = shift; $plugin->registry({ tags => { modifier => { quote => &_quote_str, }, }, }); } sub _quote_str { # $textにフィルターを適用する文字列 # $argに属性の値(quote="1"なら1) # $ctxにMT::Template::Contextオブジェクト # がそれぞれ渡される。 my ($text, $arg, $ctx) = @_; # クォートした文字列を返す return '‘' . $text . '’'; }
となります。
これで、「ブログ記事の詳細」テンプレートなどで、例えば
<$MTEntryBody$>
に
<$MTEntryBody quote="1"$>
とすると、エントリー本文の箇所をMTが生成する時にこのグローバルフィルターが呼ばれて、エントリー本文を‘と’で囲んだ値にして返します。
この例ではquoteに指定する値で処理は分岐していないので、
<$MTEntryBody quote=""$>
といった指定でもフィルターは動作します。
エントリー内変数の置換 †
エントリー内変数の置換は、グローバルフィルターのハンドラ内で置換処理を実装するだけです。
例えば、
<!-- Hello -->
というフォーマットの変数を定義して、これを「こんにちは」に変換するには、属性名 jp_hello、ハンドラ _jp_helloとすると次のようになると思います(動作未検証)。
sub init_registry { my $plugin = shift; $plugin->registry({ tags => { modifier => { jp_hello => &_jp_hello, }, }, }); } sub _jp_hello { my ($text, $arg, $ctx) = @_; $jp_hello_str = 'こんにちは'; $text =~ s/<\!-- Hello -->/$jp_hello_str/og; return $text; }
このようにグローバルフィルターで置換処理を行うメリットは次の通りです。
- 任意のファンクションタグに対して作用させることができる
- グローバルフィルターに与える引数(属性値)に応じて挙動を分けることができる
- 自由な場所に独自変数を配置できる(<!-- Hello -->をエントリーの冒頭においてもいいし、末尾においてもいいといったこと)
- 再構築する場合でも、エントリーを保存するだけの場合でも、対象の構築処理が走るタイミングで常に実行させられる
- 元データ(DBに保存されているエントリー等のデータ)は独自変数を含んだ状態で保持されるため、編集画面上で柔軟に再設定可能
- MT::Template::Contextオブジェクトも利用すれば、コンテキスト(文脈)に応じた処理のふりわけも可能
- ハンドラからはMT::*の各クラス、オブジェクトを利用可能
再構築をプラグインから呼び出す †
$app->rebuild_theseメソッドを使います。
my @entry_ids = qw(2 4 10); # 再構築するエントリーIDを指定 my %param = map { $_ => 1 } @entry_ids; # ハッシュに変換 app->rebuild_these( \%param, how => NEW_PHASE ); # 再構築実行
how => NEW_PHASEを渡すことで再構築中の表示が返されます(rebuilding.tmplが直ちに読み込まれて返されます)
A-Formでは以下のように、rebuild_new_phaseというモードに再構築したいidと戻り先のmodeを指定してアクセスさせています。
my $return_arg = $app->uri_params('mode' => $return_mode, 'args' => \%return_args); $return_arg =~ s/^\?//; return $app->redirect( $app->uri( mode => 'rebuild_new_phase', args => { id => \@ids, return_args => $return_arg } ) );
rebuild_new_phaseモードはrebuild_theseを呼び出します。
これによって、
- エントリーにA-Formの変数<!-- aformXXX -->をグローバルフィルターで読み込み
- 埋め込まれているA-FormのIDを取得し、A-Formと埋め込み先のエントリーの関連を保持するMT::AFormEntryモデルからこのA-Formが埋め込まれている他のエントリーIDを取得する
- 取得したエントリーIDをrebuild_new_phaseにidパラメータで渡すことで、このA-Formが埋め込まれているエントリーを全て再構築する。
という処理を行っています。
次回予定 †
次回は(まだちょっと未定ですが)、国際化の方法、またはregistryメソッドのリファレンス一通り見ることを行いたいと思います。registryメソッドの場合は長くなると思いますので、2〜3回にわけるかもしれません。