MT4でMT::Objectを継承したサブクラスを作ってDBのテーブルを拡張する(メモ)。
公開日 : 2007-09-03 19:59:46
メモ。
MTの「コア」のテーブルにカラムを追加するのってどうなのよ! バージョンアップの際にも困るんでないの? ってかプラグインみたいな気軽に付けたり外したりするものでカラムを追加するのってさぁ...というお話があがっているので素直にMT4でMT::Objectを継承したサブクラスを作ってDBのテーブルを拡張する方法でやってみようかと。
モデルは数日前に作った「TemplateSelector」プラグイン。
# 何とか出来たっぽいけど効率が良いとは言えないなぁ...ということでテストも不十分だしまだ公開はしない。あくまでも備忘録です。
Selector.pm をプラグインフォルダの lib/TemplateSelector 以下に設置
plugins/TemplateSelector/lib/TemplateSelector/Selector.pm
Selector.pm
package TemplateSelector::Selector;
use strict;
@TemplateSelector::Selector::ISA = qw( MT::Object );
__PACKAGE__->install_properties({
column_defs => {
'id' => 'integer not null auto_increment',
'blog_id' => 'integer not null',
'entry_id' => 'integer not null',
'template_name' => 'string(255)',
},
indexes => {
blog_id => 1,
entry_id => 1,
template_name => 1,
},
child_of => 'MT::Entry',
datasource => 'selector',
primary_key => 'id',
});
1;
TemplateSelector.pl
use TemplateSelector::Selector;
中略
sub init_registry {
my $plugin = shift;
$plugin->registry({
object_types => {
'selector' => 'TemplateSelector::Selector',
},
以下略
これで、プラグインを「new」する時に schema_version を指定してやればUpgraderが起動してデータベースにテーブルを追加してくれる。
Selector.pmで「child_of => 'MT::Entry',」とすることで、該当のエントリーが削除されたらSelectorの該当するフィールドを削除してくれる。このあたりはさすが!
entry_idで紐付をして、エントリーがどのテンプレートを選択しているかを template_name に突っ込みたいが、これはさすがに自前でコードを書く必要がある。カラムの拡張ならフォームのname属性をtemplate_nameにしたセレクトメニューとかチェックボックスを用意すれば保存時に勝手に保存してくれる。これが便利すぎて嫌になる(カラムを拡張する誘惑に負けそうになる)。
気を取り直して、コード部分。
init_registryにコールバックを登録する。
- 'MT::App::CMS::template_source.edit_entry' → セレクトメニューを登録するTransformer
- 'cms_post_save.entry'→エントリーが保存された後処理(このタイミングで処理する)
TemplateSelector.pl (続き)
callbacks => {
'MT::App::CMS::template_source.edit_entry'
=> ¥&_add_template_selector,
'cms_post_save.entry'
=> ¥&_entry_selector,
中略
sub _entry_selector {
my ($eh, $app, $obj, $original) = @_;
my $q = $app->param;
my $template_name = $q->param('template_name');
my $id = $obj->id;
my $sel = TemplateSelector::Selector->load({ entry_id => $id });
if ($template_name) {
unless (defined $sel) {
$sel = TemplateSelector::Selector->new;
$sel->entry_id($id);
}
$sel->template_name($template_name);
$sel->blog_id($app->blog->id);
$sel->save or die $sel->errstr;
} else {
if (defined $sel) {
$sel->remove or die $sel->errstr;
}
}
}
これで、エントリーが保存されるのと同時に selector_template_name が保存されるようになった。
これで「出来た!」という程世の中甘くなかったよ。問題はテンプレートを選択した時のプレビュー(「確認」ボタンクリックした時の画面)。プレビューではテンプレートが選択されたテンプレートになってくれない。一旦エントリーを保存すれば良いわけだけど、これは多分「あり得ない」仕様だろうなぁ。テンプレートを切り替えてもエントリー公開するまでデザインが確認できないなんて!
ということで、プレビューも自前で実装(何とかならんものか)。でもこれやっとかないと「フィールド拡張」も出来ないし。
コールバックに以下を追加。
TemplateSelector.pl (さらに続き)
'MT::App::CMS::template_output.preview_strip'
=> ¥&_style_preview,
CMS.pmのコードを読むと、未保存のエントリーのプレビュー時には entry_id(-1) としてるようなので、一時的に TemplateSelector::Selector->new;して entry_id(-1) として selector_template_name にテンプレート名をセットして保存、プレビュー用のHTMLをbuildしたらそのレコードは削除することにした。
sub _style_preview {
my ($eh, $app, $tmpl) = @_;
my $q = $app->param;
my $id = $q->param('id');
my $template_name = $q->param('template_name');
my $sel; my $org_templ_name; my $tmp_sel;
unless ($id) {
$sel = TemplateSelector::Selector->new;
$sel->id(-1);
$sel->entry_id(-1);
$sel->template_name($template_name);
$sel->blog_id($app->blog->id);
$sel->save or die $sel->errstr;
} else {
$tmp_sel = TemplateSelector::Selector->load( { entry_id => $id } );
if (defined $tmp_sel) {
$tmp_sel->template_name($template_name);
}
}
my $blog = $app->blog;
my $blog_id = $blog->id;
my $tmap = MT::TemplateMap->load(
{ blog_id => $blog_id,
archive_type => 'Individual',
is_preferred => 1
},);
my $template = MT::Template->load({id => $tmap->template_id});
my $preview_tmpl = $app->translate_templatized($template->output);
$$tmpl = $preview_tmpl;
unless ($id) {
$sel->remove or die $sel->errstr;
}
}
とりあえず「保存」ボタンとか「エントリー編集画面に戻る」ボタンが無いので「ブラウザのバックボタン」で戻ってね状態だけどプレビューにテンプレートの変更が反映されるようになった。フーーーッ! 結構面倒だなぁ、というのが正直な感想。
MT3.xでも有効な例はこちらに↓。