ついに出た!最新Perlフレームワーク「Ark」徹底解剖

第3回Ark チュートリアル:応用編(その1)

前回はArkを使用した開発方法と開発の一連の流れを説明しました。今回から2回に分けてより実用的なサンプルアプリケーションを作成しながら、Arkの機能をより詳しく紹介します。

掲示板の概要

今回作成するアプリケーションは、OpenID認証を使用したシンプルな掲示板アプリケーションです。

モデルとビュー

前回はコントローラだけしか使用しませんでした。今回はモデルとビューもすべて使用します。

Arkは、モデルやビューなど自分の使いたいモジュールを組み合わせて使用することができるようになっています。コントローラ以外は、CPANにある好きなモジュールを使えるということです。 これは膨大な量のCPANモジュールを持つPerlならではの発想かもしれません。

 ビュー/モデルには自分の好きなモジュールを使用することができる
図 ビュー/モデルには自分の好きなモジュールを使用することができる

モデル

モデルはアプリケーションのロジックを定義するクラスです。

上記の例ではデータベースやキャッシュ周りのモジュールをモデルとして使用するという例を挙げましたが、実際にはArkではモデルにアプリケーションロジックを書くこと、またその処理をArkアプリケーションのモデルクラスに書くのではなく、単体の外部モジュールとして実装することを推奨しています。

この方法は、ロジックをArkアプリケーションから切り離し単体で使用できるようにすることで、テストがしやすかったり、コマンドラインスクリプトからも同じロジックを使用可能などのメリットがあるためです。

最近ではCatalystでもこの方法を推奨するようになってきていて、モダンPerl入門⁠4.4 効率的なモデルの書き方)という書籍でも詳しく解説されています。

このモデルの方法をサポートするために、Arkでは、外部モジュールをモデルとして使用するためのベースクラスにArk::Model::Adaptorという物を用意しています。

このクラスを使用すると、以下のようなコードで外部モジュールを簡単にArkモデルとすることができます。

package MyApp::Model::Cache
use Ark 'Model::Adaptor';

__PACKAGE__->config(
    class => 'Cache::Memcached',
    args  => { servers => ['127.0.0.1:11211'] },
);

1;

このコードは Cache::Memcached をモデルとして使用する例です。こうするとコントローラから

$c->model('Cache')

でCache::Memcachedオブジェクトにアクセスできます。

この機能を使用し、アプリケーションのロジックはすべて外部モジュールに定義するようにします。

ビュー

ビューはWebアプリケーションの最終出力部分を司るクラスです。テンプレートエンジンを使用して出力するHTMLを作成したり、JSONやXMLなどのシリアライザモジュールを使用しそれらの形式のデータを作成したりということを担当します。

こちらもモデルと同じようにアダプターを使用して外部モジュールに丸投げする、といった方法も可能なのですが、ビューはもうすこしArkに密接に連携していたほうが使いやすいため少しラッピングしたものを用意して使用します。

現在のバージョンでは、Text::MicroTemplateというテンプレートエンジンに対応したArk::View::MTというビューが用意されています。

プラグイン

プラグインはセッション機能、認証機能などWebアプリケーションでよく必要になる機能を実装したコンポーネントです。これらをロードすることで簡単にそれらの機能を追加していくことができます。

今回はログイン処理のために

  • セッションプラグイン
  • 認証プラグイン

を使用します。

アプリケーションの作成

それではアプリケーションを作っていきましょう。今回作るアプリケーションのソースコード全体はgithubに上げてありますので、そちらも併せて参照ください。

依存モジュール

今回作成するアプリケーションは、Ark インストール時にインストールされるモジュール以外の以下のモジュールにも依存しています。

  • DBIx::Class::Schema::Loader(DB接続に使用)
  • DBD::SQLite(SQLiteデータベース)
  • Net::OpenID::Consumer(OpenID認証に使用)
  • LWPx::ParanoidAgent(OpenID認証に使用)
  • DateTime(日付データに使用)

作業を進める前にこれらのモジュールをインストールしてください。

モデルの作成

まずアプリケーションのロジックを作ります。クラス名はMiniBBS::Service::BBSとします。

最初にこのロジックのインタフェースを考えましょう。こういう感じで使いたいというのをイメージしつつ、このクラスをどういう風に使いたいかというのを考えてみます。

# 初期化
my $bbs = MiniBBS::Service::BBS->new( connect_info => [DB接続情報] );

# BBSにメッセージを投稿
my $new_message = $bbs->add_message({
    user => 'ユーザー名',
    body => '投稿メッセージ',
});

# BBSメッセージを一覧
my $messages = $bbs->messages;

こんな感じで使えたらいいのではないでしょうか。次にこれを実装していきますが、実際にコードを書く前にこのイメージコードをテストコードまで落とし込んでおくと実装が楽になります。

t/service_bbs.tというファイルがテストコード化したものです。そして、このテストを満たすように実装したコードが lib/MiniBBS/Service/BBS.pm となっています。

このようにモデルを外部モジュールとして単体で使用できる物にすることで、再利用しやすいものになったり、テストがしやすくなったりすると言う利点があります。

この実装をModel::Adaptorを使用してArkのモデルとします。モデルのひな形も前回同様に ark.pl を使用して作成することができます。

$ ark.pl model BBS Model::Adaptor
Creating directory .
Creating lib/MiniBBS/Model/BBS.pm

このコマンドでlib/MiniBBS/Model/BBS.pmにModel::Adaptorを使用したモデルのひな形が作られます。ファイルの内容はこのようになっています。

package MiniBBS::Model::BBS;
use Ark 'Model::Adaptor';

1;

ここに接続するクラスの情報を加えるとこのようになります。

package MiniBBS::Model::BBS;
use Ark 'Model::Adaptor';

__PACKAGE__->config(
    class => 'MiniBBS::Service::BBS',
    args  => { connect_info => ['dbi:SQLite:' . MiniBBS->path_to('minibbs.db') ] },
    deref => 1,
);

1;

この設定ではDBへの接続にMiniBBS->path_to('minibbs.db')という表記でパスを指定しています。このpath_to関数は、Arkのユーティリティ関数で、Arkアプリケーションのホームディレクトリからのパスを返す関数です。ですので、この場合アプリケーションホームディレクトリ直下のminibbs.dbというファイルをデータベースとして使用するということになります。

では、そのminibbs.dbを作っておきましょう。データベースの定義はminibbs.sqlite.sqlというファイルに定義してあります。それをもとに SQLite データベースを作るには、以下のコマンドを実行します。

$ sqlite3 minibbs.db < minibbs.sqlite.sql

これでminibbs.sqlite.sqlという定義を元に、minibbs.dbができあがります。

テンプレートを使用

モデルが定義できたので、次はテンプレートを使用するためにビューをセットアップしましょう。今回は、Text::MicroTemplateをテンプレートして使用します。以下のコマンドを入力してください。

$ ark.pl view MT View::MT

このコマンドは、Ark::View::MTを継承したビューをMTという名前で作成するという意味で、実行後は、MiniBBS::View::MTというクラスができます。

このテンプレートビューの使い方は、コントローラの中で

$c->view('MT')->template('template_name');
$c->forward( $c->view('MT') );

とビュークラスにforwardする方法と、

my $body = $c->view('MT')->render('template_name');
$c->res->body( $body );

テンプレートをレンダリングした結果を自分でレスポンスに入れる方法があります。今回は前者の方法を使用します。

Rootアクションに以下のコードを加えます。

sub end :Private {
    my ($self, $c) = @_;

    unless ($c->res->body or $c->res->status =~ /^3\d\d/) {
        $c->forward( $c->view('MT') );
    }
}

endアクションはコントローラディスパッチのあとに呼ばれる特別なアクションです。

ここではコントローラがbodyを埋めていなかったらテンプレートに処理を渡す、という処理を加えています。

この後、ログイン処理の実装、モデルの利用といった内容へと進みます.詳しくは次回紹介しますので、お楽しみに!

おすすめ記事

記事・ニュース一覧