MTEntryNext,Previousの拡張(とか改良?とか)。
公開日 : 2008-11-19 17:24:40
# 何回も書いてる気がするなぁ、これ。
残念ながら...かなりしんどいことになる気がします。エントリーが1,000あって、最初と最後のエントリーだけが「カテゴリーA」に属していて、500番目のエントリーを「カテゴリーA」にしよう、と思ったら(伝わるかな?)
my $terms;
$terms->{category_id} = $cat->id;
my $prev = $e->previous(1, $terms);
my $res = '';
while ($prev && !$prev->is_in_category($cat)){
$terms->{category_id} = $cat->id;
$prev = $prev->previous(1, $terms);
}
500番目のエントリーから始まって、ひとつ前エントリーを読み込んで(ここで1回SQL投げる)のカテゴリチェック、違ったら次のエントリーの、ってのを500回程繰り返してエントリー1まで来て、お! あったあった。で、今度はNext処理で500回程...(以下略...ってか、これ以前に500エラーになるかもしれません)
いささか極端な例ですが、いずれにしても効率が良くありません (この件については以前にも書いてますね)。
- 同一カテゴリーの前後のエントリーを出力するPreviousNextInCategory互換プラグイン。 (Junnama Online (Mirror))
- KOFの会場にACアダプタ忘れて来て凹む。 (Junnama Online (Mirror))
ちなみに、$terms->{category_id}は効きません(多分(追記:MT2.x?の頃は効いたのではないかな。category_idがmt_entryテーブルのカラムだった時代))。$terms->{by_category} が指定できるっぽいですがMT4.2ではエラーになります(MT4.1ならOK。そもそも4.1ならドキュメントにはありませんが by_category="1" と by_author="1" がテンプレートタグのモディファイアで指定できるようになっています)。
本題。
/lib/MT/Object.pmの sub nextprev が4.1→4.2で変わっていて、
# Selecting the adjacent object can be tricky since timestamps
# are not necessarily unique for entries. If we find that the
# next/previous object has a matching timestamp, keep selecting entries
# to select all entries with the same timestamp, then compare them using
# id as a secondary sort column.
ああ、これ考えてたんだ...全く同じタイムスタンプのエントリーが複数あったときにどーすんだっていう件。4.1ではエントリーをループの中で比較して、タイムスタンプが同じだったらidで比較してるみたい。MT4.2ではSQL一発にシンプルに変更されているのですが、おそらくこの部分が関係して<MTEntryNext by_category="1">でウチの環境ではエラーを吐いてしまいます。ドキュメントには(多分)ないのでバグではなく仕様? なのかもしれないけど、標準でサポートされると幸せになれる人が多いかも。
で、もう一つ。not指定してるので確かにそのエントリー自身は出て来ないですが同一タイムスタンプの時の挙動(前後の指定)が (ウチの環境では) おかしい (複数のページで同じエントリーが出てくる)。
レアケースっていえばレアケースだけど、気持ち悪いので作りました。
- mt:entrynext,mt:entryprevious,mt:pagenext,mt:pagepreviousタグを上書きします。 同じタイムスタンプのエントリーが複数あったときはentry_idで比較して順番を決めます。
- by_category="1" と by_author="1" が指定できます(同一カテゴリー/投稿者のエントリーの前後を取得できます)。
- by_field="modified_on"のようにソートのカラムを指定できます(デフォルトはcreated_on)
例:
<mt:entrynext by_author="1" by_category="1" by_field="created_on">
<a href="<mt:entrypermalink>"><mt:entrytitle="escape="html"></a>
</mt:entrynext>
21:00追記
よく考えたら2つのキーで同時にソートできるわ。
$terms->{ id } = { '<' => $entry->id };
$params->{ limit } = 1;
以下修正箇所。これでload_iterでループさせる必要がなくなった。最多でもオブジェクト2つから特定できるようになったな。これでどうでしょう?
if ( $count > 1 ) {
if ( $meth eq 'next' ) {
$terms->{ id } = { '<' => $entry->id };
} else {
$terms->{ id } = { '>' => $entry->id };
}
$params->{ limit } = 1;
my $e = $class->load( $terms, $params );
return $e if defined $e;
# my $iter = $class->load_iter( $terms, $params );
# my $match;
# while ( my $e = $iter->() ) {
# return $e if $match;
# last if $match;
# if ( $e->id == $entry->id ) {
# $match = 1;
# }
# }
}