Movable Typeオブジェクトのcache_propertyについて
Movable Typeオブジェクトのcache_propertyメソッドについて紹介します。
1.概要
cache_propertyはMT::Objectに定義されているメソッドで、実行結果やデータのキャッシュを行いたい場合に利用します。キャッシュは1回のリクエスト内でのみ有効です。用途としては次の2パターンがあるようです。
- データベースへのアクセスを減らしたい
- データをリクエスト内で持ちまわりたい
2.cache_propertyへの設定
1つめの利用方法では次のように設定します。1つめのパラメータがキー、2つめのパラメータにはコードリファレンスを設定します。実行結果がキャッシュされていればキャッシュを返却し、そうでない場合はコードを実行しないという機能をもっています。
$obj->cache_property( $key, $code );
MT::Comment::parentでは次のように使われています。
sub parent {
my $comment = shift;
$comment->cache_property(
'parent',
sub {
if ( $comment->parent_id ) {
return MT::Comment->load( $comment->parent_id );
}
}
);
}
2つめの利用方法では次のように設定します。例はMT::CMS::Entry::saveで、カテゴリデータを$objに保存する場合です。
$obj->cache_property( 'category', undef, $cat );
3.cache_propertyからの取得
取得は、いずれの場合もキーを設定します。
$obj->cache_property( $key );
前述のカテゴリデータの取得は次のように行います。
my $cat = $obj->cache_property( 'category' );
4.キャッシュのクリア
キャッシュをすべてクリアしたい場合は、clear_cacheを実行します。
$obj->clear_cache();
5.注意事項
コードを実行するパターンでは試していませんが、データの保存時にcache_propertyが使えるのは、プライマリキーが存在する場合のみのようです。言い換えると、データベース保存前の$objには一意のIDが付与されていないので、その状態でcache_propertyを実行するとエラーになるようです。
以上です。こういう記事を書いたときは何かの伏線と思われることが多いのですが、そのとおりです(笑)。
Movable Typeでオブジェクトデータをそのまま取得する
Movable Typeで、デーtベースに定義されているテーブルのフィールド(オブジェクトデータ)をそのまま取得する方法です。
Movable Typeのブログ記事やブログなど、各オブジェクトのデータをPerlで取得するには、次のように記述します。下はブログ記事ID「1」のブログ記事タイトルを取得する例です。
use MT::Entry;
my $entry_id = '1';
my $entry = MT::Entry->load( $entry_id );
my $title = $entry->title;
ところで、Movable Type 5における、ブログのサイトURLやサイトパスは、ウェブサイトのサイトURLとサイトパスと結合するため、データベースには「/::/+サブディレクトリ」という形式で保存されています。
以下は、phpMyAdminで参照したmt_blogのサイトURL(blog_site_url)です。一番上がウェブサイトURLで、その下の2つは、ウェブサイトに属するブログのブログURLです。真ん中のブログのブログURLは「http://user-domain/1/」、一番下のブログのブログURLは「http://user-domain/2/」となります。

サブドメインの場合は「サブドメイン+/::/」となります。

このブログURLのデータを、「/::/」が付与されたまま取得したい場合、
use MT::Blog;
my $blog_id = '2';
my $blog = MT::Blog->load( $blog_id );
my $site_url = $blog->site_url;
と記述しても取得することができず、通常のURLとなります。
これは、ブログのサイトパスを取得する際に使う、MT::Blog::site_url内で親ウェブサイトのパスと結合する処理になっているためです(下)。
sub site_url {
my $blog = shift;
if (@_) {
return $blog->SUPER::site_url(@_);
} elsif ( $blog->is_dynamic ) {
my $cfg = MT->config;
my $path = $cfg->CGIPath;
if ($path =~ m!^/!) {
# relative path, prepend blog domain
my ($blog_domain) = $blog->archive_url =~ m|(.+://[^/]+)|;
$path = $blog_domain . $path;
}
$path .= '/' unless $path =~ m{/$};
return $path;
} else {
my $url = '';
if ($blog->is_blog()) {
if (my $website = $blog->website()) {
$url = $website->SUPER::site_url;
}
else {
# FIXME: there are a few occasions where
# a blog does not have its parent, like (bugid:102749)
return $blog->SUPER::site_url;
}
my @paths = $blog->raw_site_url;
if ( 2 == @paths ) {
if ( $paths[0] ) {
$url =~ s!^(https?)://(.+)/$!$1://$paths[0]$2/!;
}
if ( $paths[1] ) {
$url = MT::Util::caturl( $url, $paths[1] );
}
}
else {
$url = MT::Util::caturl( $url, $paths[0] );
}
}
else {
$url = $blog->SUPER::site_url;
}
return $url;
}
}
前置きが長くなりましたが、データベース上のデータをそのまま取得するには、Data::ObjectDriver::BaseObject::columnを利用し、columnのパラメータに、取得したいフィールドのフィールド名を指定します。
use MT::Blog;
my $blog_id = '2';
my $blog = MT::Blog->load( $blog_id );
my $site_url = $blog->column('site_url');
Data::ObjectDriver::BaseObjectは、MT::Objectが継承しているので、ソースコード内で意識する必要はありません。