MT4.xプラグイン作成/新しいモデルオブジェクトの作成 http://www.ark-web.jp/sandbox/wiki/302.html
MT::ObjectとMT::Objectを継承する利点 †
MTではストレージ(DBMファイルやDB)にシリアライズ/保存するすべてのオブジェクトは全てMT::Objectをベースクラスとして表現されています。
たとえば、エントリーを表すMT::EntryはMT::Objectを継承していて、DBを利用している場合であればmt_entryテーブルに紐付けられています。これによって、mt_entryにある各カラムの値はMT::Entryを使って次のようにアクセスできます。
# entry_id=1のエントリーを取得
my $entry = MT::Entry->load({id => 1});
# タイトルを取得(DB利用時であればmt_entry.titleの値が取得される)
$title = $entry->title;
# タイトル変更
$entry->title('新しいタイトル');
# 変更を保存
$entry->save or die $entry->errstr;
このようにMT::Objectを継承したクラス群はMTにおいてMVCモデルにおけるモデルクラス(モデルオブジェクト)の役割を果たしています。また、MT::Objectはユーザ(ここでは開発者)に対して次の利点をもたらします。
- ストレージを意識しないで済む、またDB利用時であってもSQLを書く必要がない
- MT::Objectによる(上の例のloadメソッドやsaveメソッドなどの)共通したインタフェースで各モデルを操作できる
- モデルのプロパティを簡単に取得/変更できる
そして、ユーザはMT::Objectを継承した新しいモデルを作成することもできます。
しかも、この方法を使うことでユーザはDBを使っている場合でも、DBを直接操作することなく、テーブル、カラムの追加、変更を行うことができ、DBのアップグレードも自動で行うような仕組みを利用できます。
モデルオブジェクトの作成 †
例として、商品というモデルの作成を考えてみます。MTベースのECシステムなどを考える場合に作成されそうですね^^
以下の設定で作成します。
| モデル名 | Product |
| クラス | MT::Product |
| ファイルパス(MTのインストールディレクトリからの相対パス | plugins/Product/lib/MT/Product.pm |
ファイルパスをpluginsの配下にしていますが、これはPluginとして作成することで、
- インストール/アンインストールを容易にする
(plugins/Productディレクトリごと消せばそれでアンインストールできる) - DBの自動アップグレードを利用できる
というメリットがあるためにそのようにしています。
参考:MovableType拡張プラグラミングに関する10の良い習慣。
※ plugins/Productのディレクトリ名はたまたまモデル名と一致させていますが、他の名前でも問題ありません。このディレクトリ名はプラグイン名に一致するので、例えばプラグイン名をShopにするのであれば、Productモデルはplugins/Shop/lib/MT/Product.pmに作成すればOKです。
Productのデータ構造はIDと商品名、商品説明、販売可能日、価格といったシンプルな形にしてみます。
| プロパティ | 型 | 属性名(意味) |
| id | integer not null | ID |
| name | string(255) not null | 商品名 |
| description | text not null | 商品説明 |
| available_at | datetime | 販売可能日 |
| price | integer not null | 価格 |
型には論理値を示すbooleanやtimestamp、smallint、bigint、float、blob等が使えます。
※ lib/MT/ObjectDriver/DDL.pmのdb2type()を見て調べているので、あやまりがあるかもしれません。ドキュメメントが見つからず・・・
以上から、MT::Productsクラス(plugins/Product/lib/MT/Product.pm)は次のようになります。
1: package MT::Product;
2:
3: use strict;
4:
5: use MT::Object;
6: @MT::Product::ISA = qw(MT::Object);
7:
8: __PACKAGE__->install_properties({
9: column_defs => {
10: 'id' => 'integer not null',
11: 'name' => 'string(255) not null',
12: 'description' => 'text not null',
13: 'available_at' => 'datetime',
14: 'price' => 'integer not null',
15: },
16: indexes => {
17: 'id' => 1,
18: 'available_at' => 1,
19: },
20: audit => 1,
21: datasource => 'product',
22: primary_key => 'id'
23: });
24:
25: 1;
install_propertiesメソッドのkey = column_defsにデータ構造をプロパティ => 型のハッシュでセットします。
indexesはindexをはるプロパティを指定します。indexに対応しているDBであればインデックスが作成されます。
プラグインの作成と自動アップグレード †
作成したモデルを利用するプラグインを作成します。
クラス名、ファイル名は何でもよいですが、以下の設定にしておきます。
| クラス名 | MT::Plugin::Product |
| プラグイン | plugins/product.pl |
プラグインでは
use vars qw( $VERSION $SCHEMA_VERSION ); $SCHEMA_VERSION = '0.2';
のように$SCHEMA_VERSIONを定義し、プラグインオブジェクトのnewで
my $plugin = new MT::Plugin::Product({
name => '<MT_TRANS phrase=\'InquiryForm Plugin\'>',
:
schema_version => $SCHEMA_VERSION,
:
object_classes => [
'MT::Product',
],
});
のようにschema_versionとobject_classesプロパティを指定します。
object_classesには利用するモデルクラス名を配列の参照で指定します。複数のモデルクラスの指定も可能です。そして、schema_versionにはこのプラグインのDBスキーマ(≒利用するモデルクラス)のバージョンを表現します。
後は、通常のプラグインと作り方は何も変わりません。プラグインを作成した後、mt.cgiにブラウザからアクセスすると、DBアップグレードを促す画面が表示され、そのままアップグレードが可能になります。
また、開発を進めていく中で、product.plが利用しているモデルクラスのスキーマが変化したとします。その時は、product.plの$SCHEMA_VERSIONをあげてやれば、再度mt.cgiにアクセスした時に再びDBアップグレードを促す画面が表示されます。$SCHEMA_VERSIONに与えるバージョン番号の採番ルールは自分で決めてよいようです。少なくとも数値として上がっていった場合にはバージョンアップとみなして、アップグレードが走ります。
![[PukiWiki] [PukiWiki]](image/sandbox.gif)



