MT::ObjectこそがMTの本質であると勝手に思っている。
公開日 : 2007-12-16 02:27:47
MTとは何だ?
MTって(あなたにとって)何? って聞かれたなら、僕は『MTとは「MT::Object」である』と答えるかな。
とあるけれど、これこそが MTの本質なのですよ。きっと。
MT::Entry とか MT::Blog とか MT::Category とかみんな MT::Object のサブクラスであり、オリジナルのクラスを作ることも簡単にできる。
MT::Object についてちょっと書いてみる。
MTOSによって、これがオープンソースになるのです。だからMTOSは「ただで使えるブログソフト」じゃない。そんなことをちょっと書いてみたい。ここから、MT中毒患者の告白です。
#!/usr/bin/perl -w
use strict;
use lib '/path/to/mt/lib';
use MT;
my $mt = MT->new(Config => '/path/to/mt/mt-config.cgi');
print "content-type: text/plain; charset=utf-8¥n¥n";
my @entries = MT::Entry->load();
foreach my $entry (@entries) {
print $entry->title . "¥t" . $entry->permalink . "¥n";
}
すべてはここから始まるっていうか、最初はこれでPermalinkを出力してPHPで読み込んでDBを操作ってやってたんだね。1年程前は。それが今じゃすっかりヘビーユーザーですよ。ということで MT::Objectの扱い方についてちょっと掘り下げてみるよ。
このスクリプトでやっていることはすべてのエントリーのタイトルとURLをタブで区切って出力する。それだけ。MT::Entry->load();でつまりすべてのエントリーを読み込んでいる。
(この後は面倒なので先頭の6行は省略します。)
では次。BlogのIDが「1」で「公開の状態」が「公開」(下書きじゃなくて) のエントリーだけを読み込む場合。
my @entries = MT::Entry->load({ blog_id => 1,
status => 2,
});
foreach my $entry (@entries) {
print $entry->title . "¥t" . $entry->permalink . "¥n";
}
以後、最後の3行も省略します。同じなので。
status => 2 ってのは「公開」状態を指すのだけど、以下のように書くことも出来る。
MT::Entry::RELEASE()
即ちMTで定義されているステータスが「公開」なエントリー (ブログ記事) ということね。つまり以下のように書くことができる。
my @entries = MT::Entry->load({ blog_id => 1,
status => MT::Entry::RELEASE(),
});
ついでに。blog_id => 1 って決めうちするのもなんだから、blogもMTに登録されているのを1つ読み込んでそのブログの記事一覧を取得するように変更してみる。
my $blog = MT::Blog->load( undef, { limit => 1 } );
my $blog_id = $blog->id;
my @entries = MT::Entry->load( { blog_id => $blog_id,
status => MT::Entry::RELEASE(),
} );
loadメソッドでオブジェクトを読む時は、ちと注意しないといけない。読み込むオブジェクトが半端でないレコードを持ってる時には、大量の値をメモリに読み込んでいまうので遅くなったりするのだ(なので limit => 1 としている)。お行儀良くひとつずつ読み込むには load_iter, 数を数えるだけなら count メソッドを使う。いずれにしても基本的に書き方は同じ。
以後、またまた面倒なので最初の2行は省略。
では次。件数やソート順を指定して読み込む。
my @entries = MT::Entry->load( { blog_id => $blog_id,
status => MT::Entry::RELEASE(),
}, {
limit => 10,
sort => 'authored_on',
direction => 'descend',
} );
公開状態のエントリーを10件、公開日(authored_on)をキーにして descend(降順=新しい順)で取得。limit, sort, directionを指定してるね。
さてさて、さらに次。範囲を指定するその1。今年の10月1日以降のエントリーを取得。start_valで日付を指定。昇順(ascend)にすれば公開日が10月1日以降のエントリーが取得できる。
my @entries = MT::Entry->load( { blog_id => $blog_id,
status => MT::Entry::RELEASE(),
}, {
sort => 'authored_on',
start_val => 20071010000000,
direction => 'ascend',
}
);
範囲指定その2。現在の月に公開されたエントリーだけを新しいものから10件取得する。「range」で範囲を指定する。
use MT::Util qw( offset_time_list start_end_month );
my @tl = offset_time_list(time, $blog);
my $ts = sprintf "%04d%02d%02d%02d%02d%02d", $tl[5]+1900, $tl[4]+1, @tl[3,2,1,0];
my ($start, $end) = start_end_month($ts);
my @entries = MT::Entry->load( { blog_id => $blog_id,
status => MT::Entry::RELEASE(),
authored_on => [$start, $end],
}, {
range => { authored_on => 1 },
limit => 10,
sort => 'authored_on',
direction => 'descend',
}
);
MT::Utilにはこういった日付関連のルーチンが色々用意されている。start_end_month ってので $start, $endには例えば今月なら 20071201000000 と 20071231235959 が返る。
range には カラム名と、常に「1」を指定。offset_time_list はブログに設定されているタイムゾーンを反映させた上で日付関連のデータを返してくれる。
さて次。テーブルの結合というか、別のテーブル (ここではエントリーとカテゴリーを紐づける) MT::Placement を結合して読み込む例。entry_id とplacement_entry_id で紐づける。
以下の例は今月に公開された category_id が 1 のエントリーを10件取得するもの。
my @entries = MT::Entry->load( { blog_id => $blog_id,
status => MT::Entry::RELEASE(),
authored_on => [$start, $end],
}, {
join => [ 'MT::Placement', 'entry_id',
{ category_id => 1 },
{ unique => 1 }
],
range => { authored_on => 1 },
limit => 10,
sort => 'authored_on',
direction => 'descend',
}
);
紐づけるためのキーは object名_id でないとうまくいかない、そういう仕様みたい(ちょっとハマった経験がある)。
こいつはつまり、SQLでいうと以下のようになる(実際にこういうSQL文をMTがDBに投げているのだ)。
SELECT DISTINCT entry_id, entry_authored_on
FROM mt_entry, mt_placement
WHERE (entry_status = '2')
AND ((entry_authored_on > '2007-12-01 00:00:00')
AND (entry_authored_on < '2007-12-31 23:59:59'))
AND (entry_class = 'entry') AND (entry_blog_id = '1')
AND (placement_category_id = '1')
AND (entry_id = placement_entry_id)
ORDER BY entry_authored_on DESC
LIMIT 10
unique => 1 とすることで、返ってくるエントリーの重複がなくなる。例えば今月にコメントがついたエントリーを読み込む場合なんかでは重複の可能性があるので unique => 1 とする。
結局のところ、このようなPerlスクリプトであれプラグインであれBootstrapアプリケーションであれ、SQLを意識すること無くましてやDBの種類を意識すること無くオブジェクトを扱えるのが Movable Type ってもんだ。
これ、面白いよ。冒頭の話に戻ると「ただで使えるMT」って捉えてるとすんごく損するよな、Web屋としては。
文系プログラマはどのようにMTと付き合っているか?
おいらはプログラマじゃなくてスーツなんだ! って、もういいか。
とにかくこれを良く読む。これを見ながら書いてますね。あとはやっぱりソースを読むことでしょうか。といってもどこをどう見るってのは長いこと触ってると分かってくるわけだが、とりあえず grep! ってな感じでもいいんではないでしょうか。
cd /path/to/mt/lib
find . -name "*.pm"|xargs grep 'MT::Entry->load'
あと、mysqlのログもよく見るね(mysqlじゃなくてもいいんだけどね)。SQLを意識しない分うまくいかないときにハマることがあって、そんな時にどんなsqlを投げてるんじゃ! ってなことでログを見て、phpMyAdmin とかでエラーを確認したりってのも良くやるよ。
まぁ、とにかくMTOSがどうなっていくのか、そして自分はどうコミットしていくのか、久しぶりにワクワクする出来事じゃないか。
ブロガー、Web屋、プログラマの皆さん、MTOSめっちゃ面白いと思いますけどどうですかね!?