2015年02月19日
細かすぎて伝わらない FieldIsNotEmpty プラグインの実装
先日の記事で、
<MTEntries field:entryenglishtitle="IS NOT EMPTY">
を実現するプラグインを紹介しました。
通常、field:foo モディファイアはカスタムフィールドの値でフィルタするのに使われるので「IS NOT EMPTY」のような条件を指定することはできません。プラグインによってこれが可能になっているのは、field:foo モディファイアに「IS NOT EMPTY」が指定されたらこういう処理をする、ということが定義されているからです。
MTEntries は MT 本体のタグなので、当然その処理は MT によって定義されています。もちろん MT のソースコードを書き換えればできますが、それではサポートを受けられなくなってしまいます。また、モディファイア field:foo の動作だけをカスタマイズできればよいので、大筋の処理を変更する必要はありません。
こういった状況で MTEntries タグの動作をカスタマイズする場合、config.yaml に以下のように既述します。
tags:
block:
Entries: >
sub {
# テンプレートタグの処理
}
MT タグを定義するプラグインを作成した経験がある場合「これだと MT 本体の MTEntries をまるごと上書きすることになる」と考えるかもしれません。
しかし、MT タグを処理する MT::Template::Context には、super_handler というメソッドがあります。config.yaml に定義した MTEntries の処理の中でこのメソッドを実行することで MT 本体の MTEntries の処理が呼ばれる仕組みです。ある程度プログラミングの経験があれば、super と聞いたときにサイヤ人よりも継承が思い浮かぶでしょう。サイヤ人が思い浮かんだとしても、それはそれでかまいません。
tags:
block:
Entries: >
sub {
my ( $ctx, $args, $cond ) = @_;
# field:foo をごにょごにょする処理
defined( my $result = $ctx->super_handler( $args, $cond ) )
or return $ctx->error( $ctx->errstr );
return $result;
}
この方法は MultiBlog プラグインが IncludeBlogs などのモディファイアを定義する用途にも利用されています。もちろんこの方法を新たなプラグインで定義しても、MultiBlog の処理も反映されます。
残すは field.foo をごにょごにょする処理です。
テンプレートタグの記述でモディファイアに指定した値はそのまま MTEntires の処理内で load 条件に渡されます。以下の処理内の $val が該当です。
if (%fields) {
# specifies we need a join with entry_meta;
# for now, we support one join
my ( $col, $val ) = %fields;
my $type = MT::Meta->metadata_by_name( $class, 'field.' . $col );
$args{join} = [
$class->meta_pkg,
undef,
{ type => 'field.' . $col,
$type->{type} => $val,
'entry_id' => \'= entry_id'
}
];
}
$val にハッシュリファレンスで { not => '' }
を渡せばカスタムフィールドの値が「空でない」を実現できます。しかしハッシュリファレンスというのはあくまでも Perl 処理内でのデータの形ですし、当然ですが MT タグの記述としてはモディファイアにはテキストしか記述できません。
そこで、値がテキスト「IS NOT EMPTY」の場合はハッシュリファレンス { not => '' }
に変換してやればよいわけです。
できあがったものはこんな感じです。
tags:
block:
Entries: >
sub {
my ( $ctx, $args, $cond ) = @_;
foreach my $arg ( keys %$args ) {
# field:foo をごにょごにょしている処理
if ( $arg =~ m/^field:./ ) {
if ( $args->{ $arg } eq 'IS NOT EMPTY' ) {
$args->{ $arg } = { not => '' };
}
}
}
defined( my $result = $ctx->super_handler( $args, $cond ) )
or return $ctx->error( $ctx->errstr );
return $result;
}
ダイナミックパブリッシングでも類似の処理を行うことができます。これについては後日紹介します。
コメントを投稿する