&pgid();
#contents
** MT::ObjectとMT::Objectを継承する利点 [#tae86890]
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のアップグレードも自動で行うような仕組みを利用できます。
** モデルオブジェクトの作成 [#s6925f51]
例として、商品というモデルの作成を考えてみます。MTベースのECシステムなどを考える場合に作成されそうですね^^
以下の設定で作成します。
|モデル名|Product|
|クラス|MT::Product|
|ファイルパス(MTのインストールディレクトリからの相対パス|plugins/Product/lib/MT/Product.pm|
ファイルパスをpluginsの配下にしていますが、これはPluginとして作成することで、
- インストール/アンインストールを容易にする
(plugins/Productディレクトリごと消せばそれでアンインストールできる)
- DBの自動アップグレードを利用できる
というメリットがあるためにそのようにしています。
参考:[[MovableType拡張プラグラミングに関する10の良い習慣。>http://junnama.alfasado.net/online/2007/07/_movablety.html]]
※ plugins/Productのディレクトリ名はたまたまモデル名と一致させていますが、他の名前でも問題ありません。このディレクトリ名はプラグイン名に一致するので、例えばプラグイン名をShopにするのであれば、Productモデルはplugins/Shop/lib/MT/Product.pmに作成すればOKです。
Productのデータ構造はIDと商品名、商品説明、販売可能日、価格といったシンプルな形にしてみます。
|プロパティ|型|属性名(意味)|h
|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であればインデックスが作成されます。
** プラグインの作成と自動アップグレード [#l64b2b96]
プラグインを作成します。
作成したモデルを利用するプラグインを作成します。
ファイル名は何でもよい
クラス名、ファイル名は何でもよいですが、以下の設定にしておきます。
|クラス名|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に与えるバージョン番号の採番ルールは自分で決めてよいようです。少なくとも数値として上がっていった場合にはバージョンアップとみなして、アップグレードが走ります。
#blikifooter(進地);