MT4.xプラグイン作成/MTのライブラリを利用した独自アプリを作る http://www.ark-web.jp/sandbox/wiki/306.html
MT4.xプラグイン作成/MTのライブラリを利用した独自アプリを作る
MT::Boostrapを利用してMTのライブラリ(とそれによって提供されるクラス、オブジェクト)を利用した独自アプリケーション(CGI)を構築することができます。
このエントリーではMT::Bootstrapを使うと何がうれしいのか、そして、MT::Bootstrapの簡単な使い方について説明します。
参照:Movable Type オブジェクト・リファレンス - MT::Bootstrap
MT::Bootstrap
MT::Bootstrapを使うと何がうれしいのか? †
MT::Bootstrapを使うことで次のようなうれしいことが!
- MT、MT::App、MT::ObjectといったMTのライブラリが提供するクラス、オブジェクトを独自アプリケーション(CGI)で利用できる
- ↑によってSQLを直接叩なんてことをせずに、MTで保持しているデータにAPI経由でアクセスできる(MT::Object様々)
- ↑からDBに依存しない実装が可能(MT::Objectが環境差を吸収してくれる)
- 導入しているPluginが独自に定義しているMT::*クラス、オブジェクトも利用できる
- HTTPヘッダの出力、GET/POSTデータの受け取り、標準出力への出力、メールの送信など定型の処理をMTに任せてしまえる
- (やったことないけど)MTのユーザ管理、認証の仕組みも利用できる
なので、例えば、MTのユーザ別に記述したブログ数を出力する「ブログいっぱい書いた人ランキング」を表示するCGIなどが簡単に作れます。
MT::Bootstrapの簡単な使い方 †
Step by StepでMT::Bootstrapの簡単な使い方を示します。
1. 本体プログラムを作成する †
WebブラウザでURLを指定されてアクセスされるスクリプトを作成します。このスクリプトがCGIアプリケーションの本体になります。コードは以下のようになります。
#!/usr/bin/perl -w use strict; use File::Basename; use lib (dirname($0) . '/') . 'lib'; use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/lib" : (dirname($0) . '/../../') . 'lib'; use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/extlib" : (dirname($0) . '/../../') . 'extlib'; use MT::Bootstrap App => 'BlogPublisherRanking';
コードはこれだけです。本体スクリプトには詳細なコードは書かずに単にMT::BootstrapにアプリケーションのMainのロジックを記述したクラス名を与えるだけです。以下、このクラスをMainクラスと呼称します。Mainクラスのクラス名はBlogPublisherRankingとしました。
use MT::Bootstrap App => 'BlogPublisherRanking';
このスクリプトを任意の名前で保存します。ここではblog_publisher_ranking.cgiとします。*1
保存したスクリプトに実行権限を与えておきます。
$ chmod a+x blog_publisher_ranking.cgi
2. Mainクラスを作成する †
Mainクラス、BlogPublisherRankingを以下のように作成します。
package BlogPublisherRanking; use strict; use MT; use MT::App; use MT::Blog; use MT::Entry; : : # 利用したいMTライブラリのクラス名を列挙する : # MT::Appクラスのサブクラスとして定義する。 @BlogPublisherRanking::ISA = qw(MT::App); sub init_request { my $app = shift; $app->SUPER::init_request(@_); $app->add_methods( BlogPublisherRanking => \&_BlogPublisherRanking ); $app->mode('BlogPublisherRanking'); $app->{requires_login} = 0; } sub _BlogPublisherRanking { my $app = shift; my $q = $app->param; : : # 色々な処理 : return '画面に表示したい文字列'; } 1;
このスクリプトをlib/配下など、blog_publisher_ranking.cgiがライブラリパスとして参照できるディレクトリにファイル名BlogPublisherRanking.pmで保存します。
Mainクラスにはアプリケーションの実際のロジックを記述していきます。
また、MainクラスはMT::Appのサブクラスとします。こうすることで、HTTPヘッダの出力、GET/POSTデータの受け取り、標準出力への出力といったCGIに特有の定型処理を自分で書く必要がなくなります。
sub init_request { my $app = shift; $app->SUPER::init_request(@_); $app->add_methods( BlogPublisherRanking => \&_BlogPublisherRanking ); $app->mode('BlogPublisherRanking'); $app->{requires_login} = 0; }
のコードで、アプリケーションに対するリクエストの取り扱いを初期化しています。
具体的には、
- app_methodsでBlogPublisherRankingというモードとこれを処理するメソッド_BlogPublisherRankingを定義し
- modeメソッドでBlogPublisherRankingを指定することでアプリケーションのモードをBlogPublisherRankingに変更し
- requires_loginに0を指定することでMTのログインなしに実行されるアプリケーションであることを明示
しています。
これによって、おおざっぱにいうと、
blog_publisher_ranking.cgiにブラウザ等でアクセス -> BlogPublisherRankingのinit_requestが実行される -> モードがBlogPublisherRankingなので、そのモードに対応した_BlogPubliserRankingが呼び出される
という処理が走ります。
そして、_BlogPubliserRankingで何らかの処理を行って、文字列を返すとその文字列がブラウザ等の画面上に表示されます。HTTPヘッダを自分で出力する必要はありません。
また、_BlogPubliserRankingでは、第一引数にMT::Appの参照を受け取ることができ、MT::App->paramでGET/POSTデータを取り出すことができます。
このファイルを./BlogPubliserRanking.pmなどのパスで保存します。
参照:
3. テンプレートのロードと出力構築 †
では、_BlogPublisherRankingの詳細を実装します。
sub _BlogPullisherRanking { my $app = shift; my $q = $app->param; # テンプレートファイルの格納ディレクトリを設定する $app->{plugin_template_path} = 'tmpl/BlogPublisherRanking'; # 以下のデータ構造を取得する関数(_get_sorted_publishers)があるとする # ( # { name => 一番エントリー数の多いユーザ名, ... }, # { name => 次にエントリー数の多いユーザ名, ... }, # : # { name => 一番エントリー数の少ないユーザ名, ... }, # ) my @publishers = &_get_sorted_publishers($app); my %param = ( 'publishers' => \@publishers, ); # テンプレートにパラメータを適応して、結果文字列(ブログいっぱい書いた人ランキング)を生成して返す return $app->build_page('blog_publisher_ranking.tmpl', \%param); }
まず、
$app->{plugin_template_path} = 'tmpl/BlogPublisherRanking';
によってテンプレートファイルを置くディレクトリパスを指定します。
ここでは、スクリプト(blog_publisher_ranking.cgi)からの相対パスでtmpl/BlogPublisherRankingというディレクトリにテンプレートを置く指定をしています。
その後、必要なデータ構造(この場合、ブログを書いたランキングでソートされたMT::Authorの配列)を生成し、テンプレートに引き渡して結果文字列を生成します。
テンプレートファイルは
my $html = $app->load_tmpl('blog_publisher_ranking.tmpl', \%param);
と指定しているので、先のplugin_template_pathの指定からtmpl/BlogPublisherRanking/blog_publisher_ranking.tmplと判断されます。
テンプレートファイルの中身は
<mt:loop name="publishers"> <$mt:var name="name"$> </mt:loop>
といった形になります*2。
return $app->build_page('blog_publisher_ranking.tmpl', \%param);
build_pageで結果を生成して返します。
4. MT::Objectのロード †
書いたエントリー数が多い順にユーザ名を返す_get_sorted_publishers関数は以下のようにできると思います。
sub _get_sorted_publishers { my $app = shift; # MT::Authorオブジェクトを全件ロードする my @authors = MT::Author->load(); # author_idとユーザ名,書いたエントリー数からなるハッシュ { id => author_id, name => ユーザ名, count => エントリー数 }の配列を生成する。 my @publishers = map { return { 'id' => $_->id, 'name' => $_->name, 'count' => MT::Entry->count({ 'author_id' => $_->id }) }; } @authors; # エントリー数でソート(降順)して返す return sort { $b->{'count'} <=> $a->{'count'} } @publishers; }
MT::AuthorもMT::EntryもMT::Objectを継承しているのでloadメソッドで簡単に取得できるのが助かるところです。
*1 このスクリプトはblog_publisher_ranking.cgiがMT本体のディレクトリに設置されているという想定でlib、およびextlibのパスを指定しています。設置場所が異なる場合はそれにあわせて、パスを変更する必要があるでしょう
*2 詳しくはMT4.xプラグイン作成/テンプレートでループを利用する方法を参照のこと