recently_commented_onが正しく機能しない
PostgreSQLをバックエンドにして、「最近のコメント」を作成しようとすると、おかしなエントリが表示されてしまいます。(MySQLの場合やSQLiteの場合はわかりません。ファイルをバックエンドにしている場合は大丈夫です。)
これは、DISTINCTの使い方が正しくないためです。大まかに言うと、MTはコメントの一覧を作成して、これを作成された日時で降順に(descend)ソートします。そしてその結果から、コメントされているエントリの一覧を作成します。このとき、ひとつのエントリに複数のコメントがあれば、当然、エントリが重複して抽出されますから、これを解消するために、DISTINCTを指定しています。ところが、DISTINCTは重複行は取り除くものの、その結果得られるエントリ一覧の順序は保証されないのです。従って、折角ソートして作った一覧を、DISTINCTが壊してしまっているのです。
とりあえず、以下のパッチをあてることで、この問題は解決します。但し、この修正を行なった後に、バックエンドをPostgreSQL以外に変更すると、おかしなことになりますので、その場合は lib/MT/Template/ContextHandlers.pm(MT-3.1xの場合はlib/MT/Template/Context.pm)をオリジナルのものに戻すようにしてください。なお、パッチはMT-3.2以降と、MT-3.1xとで微妙に違います。
余談ですが、「最近のコメント」を作るために、sort_order=“ascend”を指定するようにかいてある記事を見かけますが、このオプションは recently_commented_onには無効ですし、更にいうと、昇順(ascend)にしたら、それは最近のではなく最古のになってしまいますので、あらゆる意味で間違いです。
パッチ(MT-3.2)
*** MT-3.2-b1-ja.orig/lib/MT/ObjectDriver/DBI/postgres.pm 2005-09-02 16:13:00.000000000 +0900 --- MT-3.2-b1-ja/lib/MT/ObjectDriver/DBI/postgres.pm 2005-09-13 17:14:18.000000000 +0900 *************** *** 86,91 **** --- 86,106 ---- $sql = $s_sql . $sql; $w_sql .= ") t\n"; } + elsif ($j_args->{'aggregate_sort'}) { + ## sorting with aggregate function, + my $as_args = $j_args->{'aggregate_sort'}; + my $cols = $class->column_names; + my $s_sql = "from (select " . + join(', ', map "${tbl}_$_", @$cols) . + ", $as_args->{'function'}(${j_tbl}_$as_args->{'column'}) as ${tbl}_${j_tbl}_$as_args->{'column'}\n"; + $sql = $s_sql . $sql; + $w_sql .= "group by " . + join(',', map "${tbl}_$_", @$cols) . "\n"; + $w_sql .= ") t\n"; + my $dir = $as_args->{'direction'} && + $as_args->{'direction'} eq 'descend' ? 'desc' : 'asc'; + $w_sql .= "order by ${tbl}_${j_tbl}_$as_args->{'column'} $dir\n"; + } if (my $n = $j_args->{limit}) { $n =~ s/\D//g; ## Get rid of any non-numerics. *** MT-3.2-b1-ja.orig/lib/MT/Template/ContextHandlers.pm 2005-09-02 16:13:00.000000000 +0900 --- MT-3.2-b1-ja/lib/MT/Template/ContextHandlers.pm 2005-09-13 17:17:15.000000000 +0900 *************** *** 866,875 **** require MT::Comment; $args{'join'} = [ 'MT::Comment', 'entry_id', { blog_id => $blog_id, visible => 1 }, ! { 'sort' => 'created_on', ! direction => 'descend', ! unique => 1, ! limit => $n } ]; $no_resort = 1; } @entries = MT::Entry->load(\%terms, \%args); --- 866,875 ---- require MT::Comment; $args{'join'} = [ 'MT::Comment', 'entry_id', { blog_id => $blog_id, visible => 1 }, ! { 'aggregate_sort' => { 'column' => 'created_on', ! 'function' => 'max', ! 'direction' => 'descend' }, ! limit => $n } ]; $no_resort = 1; } @entries = MT::Entry->load(\%terms, \%args);
パッチ(MT-3.1x)
*** MT-3.121-full-ja.orig/lib/MT/ObjectDriver/DBI/postgres.pm 2004-10-01 15:18:37.000000000 +0900 --- MT-3.121-full-ja/lib/MT/ObjectDriver/DBI/postgres.pm 2005-01-18 09:54:25.000000000 +0900 *************** *** 78,83 **** --- 78,98 ---- $sql = $s_sql . $sql; $w_sql .= ") t\n"; } + elsif ($j_args->{'aggregate_sort'}) { + ## sorting with aggregate function, + my $as_args = $j_args->{'aggregate_sort'}; + my $cols = $class->column_names; + my $s_sql = "from (select " . + join(', ', map "${tbl}_$_", @$cols) . + ", $as_args->{'function'}(${j_tbl}_$as_args->{'column'}) as ${tbl}_${j_tbl}_$as_args->{'column'}\n"; + $sql = $s_sql . $sql; + $w_sql .= "group by " . + join(',', map "${tbl}_$_", @$cols) . "\n"; + $w_sql .= ") t\n"; + my $dir = $as_args->{'direction'} && + $as_args->{'direction'} eq 'descend' ? 'desc' : 'asc'; + $w_sql .= "order by ${tbl}_${j_tbl}_$as_args->{'column'} $dir\n"; + } if (my $n = $j_args->{limit}) { $n =~ s/\D//g; ## Get rid of any non-numerics. *** MT-3.121-full-ja.orig/lib/MT/Template/Context.pm 2004-10-26 17:27:53.000000000 +0900 --- MT-3.121-full-ja/lib/MT/Template/Context.pm 2005-01-18 09:52:01.000000000 +0900 *************** *** 741,749 **** } elsif (my $n = $args->{recently_commented_on}) { $args{'join'} = [ 'MT::Comment', 'entry_id', { blog_id => $blog_id, visible => 1 }, ! { 'sort' => 'created_on', ! direction => 'descend', ! unique => 1, limit => $n } ]; $no_resort = 1; } --- 741,749 ---- } elsif (my $n = $args->{recently_commented_on}) { $args{'join'} = [ 'MT::Comment', 'entry_id', { blog_id => $blog_id, visible => 1 }, ! { 'aggregate_sort' => { 'column' => 'created_on', ! 'function' => 'max', ! 'direction' => 'descend' }, limit => $n } ]; $no_resort = 1; }
MovableTypeに関してへ戻る。