前回はエントリリソースを扱うAtomPubサーバを作りました。今回は、
サンプルコードはこちらからダウンロードできます。
メディアリソースとは
前回説明したように、
エントリリソースの場合と同様に、

エントリリソースはXMLなので、
コレクションのURIに対してGETが送られると、
メディアリソースとメディアリンクエントリは、
メディアリソースを取得

メディアリソースを更新


メディアリソースかメディアリンクエントリのいずれかが削除されたときは、
テーブルの作成
メディアリソースとメディアリンクエントリを格納するテーブルを作成します。
MyBlog % sqlite3 test.db sqlite> CREATE TABLE medias ( ...> id INTEGER PRIMARY KEY, ...> edited INTEGER, ...> ...> entry_uri TEXT UNIQUE, ...> entry_body BLOB, -- XML ...> ...> media_uri TEXT UNIQUE, ...> media_body BLOB, -- Base64 ...> media_type TEXT ...> );
最初の4カラムは、
最後の3カラムにメディアリソースが格納されます。
media_
media_
media_
コレクションコントローラの作成
ヘルパスクリプトを使って、
MyBlog % perl script/myblog_create.pl controller MediaCollection Atompub::Collection
前回のエントリコレクションと同じように、
メンバの列挙(List)
列挙は前回のコレクションとほぼ同じです。フィードのひな型を取得し、
sub get_feed :Atompub(list) {
my($self, $c) = @_;
# フィード(XML::Atom::Feed) のひな型
my $feed = $self->collection_resource->body;
# mediasテーブルからメンバリソースを取得する(更新日時の新しい順)
my $rs = $c->model('DBIC::Medias')
->search({}, { order_by => 'edited DESC' });
# フィードのひな形にメディアリンクエントリを追加する
while (my $resource = $rs->next) {
my $entry = XML::Atom::Entry->new(\$resource->entry_body);
$feed->add_entry($entry);
}
# 成功したらtrueを返す
return 1;
}
メンバの追加(Create)
前回作成したエントリコレクションはエントリのみを格納しましたが、
use MIME::Base64;
sub create_resource :Atompub(create) {
my($self, $c) = @_;
# スーパークラスが自動生成したURIと更新日時を取得する
my $entry_uri = $self->media_link_entry->uri;
my $media_uri = $self->media_resource->uri;
my $edited = $self->edited->epoch; # (UNIX time形式に変換)
# POSTされたメディアリソースを取得する(バイナリデータ)
my $media = $self->media_resource->body;
# メディアリソースのメディアタイプ(image/jpegなど) を取得する
my $media_type = $self->media_resource->type;
# スーパークラスが自動生成したメディアリンクエントリ(XML::Atom::Entry) を取得する
my $entry = $self->media_link_entry->body;
# mediasテーブルにメディアリソースとメディアリンクエントリを格納する
$c->model('DBIC::Medias')->update_or_create({
edited => $edited,
entry_uri => $entry_uri,
entry_body => $entry->as_xml,
media_uri => $media_uri,
media_body => MIME::Base64::encode($media), # ASCIIに変換する
media_type => $media_type,
});
# 成功したらtrueを返す
return 1;
}
このメソッドが呼ばれる前に、
このメソッドでは、
メンバの取得(Read)
sub get_resource :Atompub(read) {
my($self, $c) = @_;
# リクエストされたURI
my $uri = $c->req->uri;
# mediasテーブルからリソースを検索する
my $rs = $c->model('DBIC::Medias')->search({
'-or' => [
{ entry_uri => $uri },
{ media_uri => $uri },
]
});
# メディアリンクエントリのURIであった場合
if ($rs->entry_uri eq $uri) {
# メディアリンクエントリをセットする
$self->media_link_entry->body( XML::Atom::Entry->new(\$rs->entry_body) );
}
# メディアリソースのURIであった場合
else {
# メディアリソースをセットする
$self->media_resource->body( MIME::Base64::decode($rs->media_body) );
$self->media_resource->type( $rs->media_type );
}
# 成功したらtrueを返す
return 1;
}
メディアリソースを扱うコレクションでは、
メンバの更新(Update)
sub update_resource :Atompub(update) {
my($self, $c) = @_;
# リクエストされた URI
my $uri = $c->req->uri;
# medias テーブルからリソースを検索する
my $rs = $c->model('DBIC::Medias')->search({
'-or' => [
{ entry_uri => $uri },
{ media_uri => $uri },
]
});
# $valsには、更新するカラムの値をセットする
my $vals = { edited => $self->edited->epoch };
# メディアリンクエントリのURIであった場合
if ($rs->entry_uri eq $uri) {
# メディアリンクエントリをセットする
$vals->{entry_body} = $self->media_link_entry->body->as_xml;
}
# メディアリソースのURIであった場合
else {
# メディアリンクエントリの更新日時(app:edited) を更新し、セットする
my $entry = XML::Atom::Entry->new(\$rs->entry_body);
$entry->edited( $self->edited->w3c );
$vals->{entry_body} = $entry->as_xml;
# メディアリソースをセットする
$vals->{media_body} = MIME::Base64::encode( $self->media_resource->body );
$vals->{media_type} = $self->media_resource->type;
}
# 更新を実行する
$rs->update($vals);
# 成功したら true を返す
return 1;
}
メンバの取得と同様に、
更新対象がメディアリンクエントリのときは、
メンバの削除(Delete)
sub delete_resource :Atompub(delete) {
my($self, $c) = @_;
# リクエストされたURI
my $uri = $c->req->uri;
# mediasテーブルからエントリを削除する
my $rs = $c->model('DBIC::Medias')->search({
'-or' => [
{ entry_uri => $uri },
{ media_uri => $uri },
]
})->delete;
# 成功したらtrueを返す
return 1;
}
メンバの取得と同様に、
以上でメディアリソースを扱うコレクションの実装が終わりました。
コレクションの設定
デフォルトでは、
エントリリソースを扱うコレクションの設定
エントリリソースのコレクションでは、
Controller::EntryCollection:
collection:
title: Diary
categories:
- fixed: yes
category:
- term: animal
- term: vegetable
- term: mineral
このように設定すると、
Atomのカテゴリには、
ここでは、
メディアリソースを扱うコレクションの設定
メディアリソースのコレクションでは、
Controller::MediaCollection:
collection:
title: Photo
accept:
- image/png
- image/jpeg
- image/gif
ここでは、
サービス文書コントローラの作成
コレクションの設定情報をクライアントに公開します。AtomPubでは、
ヘルパスクリプトを使って、
MyBlog % perl script/myblog_create.pl controller Service Atompub::Service
コレクションと異なり、
HTMLコントローラの作成
もう一息です。HTMLを表示するためのコントローラを作成して、
ヘルパスクリプトを使ってコントローラを作成します。
MyBlog % perl script/myblog_create.pl controller Html
コマンドを実行すると、
use Digest::MD5 qw(md5_hex);
sub index : Private {
my($self, $c) = @_;
# entriesテーブルからエントリを取得する(更新日時の新しい順)
my $rs = $c->model('DBIC::Entries')->search({}, { order_by => 'edited DESC' });
# テンプレート用のデータ領域($c->stash) にエントリを追加する
while (my $entry_resource = $rs->next) {
my $entry = XML::Atom::Entry->new(\$entry_resource->xml);
my $content = $entry->content->body;
utf8::encode $content;
push @{ $c->stash->{entries} }, {
link_hash => md5_hex($entry->link->href),
title => $entry->title,
updated => $entry->updated,
content => $content,
};
}
}
トップページへのアクセスは /html にリダイレクトしておきます。
sub default : Private {
my($self, $c) = @_;
$c->res->redirect('/html');
}
ビューの作成
ヘルパスクリプトを使ってビューを作成します。
MyBlog % mkdir root/src/html
テンプレートを作成し、
[% META title = 'My Blog' %]
<div class="hfeed">
[% FOREACH entry IN entries %]
<a name="[% entry.link_hash -%]">
<div class="hentry">
<h2>
<a href="#[% entry.link_hash -%]">_</a>
<span class="entry-title">
[% entry.title %]
</span>
</h2>
<div><i class="updated">[% entry.updated %]</i></div>
<div class="entry-content">[% entry.content %]</div>
</div>
</a>
[% END %]
</div>
これで写真付きブログサーバの完成です。Catalystを起動してhttp://
Windows Live Writer で投稿してみる
Windows Live Writer というAtomPubクライアントを使って、
Windows Live Writerはhttp://
- ようこそ!というダイアログでは、
「ブログを持っている」 を選択してください。ブログ種類の選択では、 「他のブログサービス」 を選びます。 - ブログのホームページとログインでは、
URLにhttp://<server>:3000/ serviceを入力してください。ユーザー名とパスワードはまだ使わないので、 適当に埋めておいてください。 - プロバイダの選択では、
「Atom Publishing Protocol」 を選択し、 Service DocumentのURLに 「http://<server>:3000/ service」 を入力します。 - 仮の記事の作成を有効にしますか?と尋ねられたら、
「いいえ」 を選んでください。 - 画像コレクションの選択では、
「My Blog - Photo」 を選択します。最後に 「完了」 をクリックします。
以上でウィザードが終了し、
タイトルと本文に何か記入して
続いて、
この連載では簡単なブログサーバを実装しただけですが、