Perl Hackers Hub

第18回Amon2によるWebアプリケーションの高速開発(3)

(1)こちら⁠2)こちらから。

スケルトンに掲示板機能を付けてみる

スケルトンを眺めているだけではおもしろくないので、スケルトンをベースに実際に掲示板機能を付けてみましょう。

掲示板のスキーマ

今回、セットアップが簡単なようにデータベースにはSQLite3を用います。sql/sqlite3.sqlに次のように書きましょう。

CREATE TABLE IF NOT EXISTS sessions (
    id CHAR(72) PRIMARY KEY,
    session_data TEXT
);

CREATE TABLE IF NOT EXISTS entry (
    entry_id INTEGER NOT NULL PRIMARY KEY,
    body varchar(255) not null
);

sessionsテーブルはセッションの保存用テーブルです。

コントローラの実装

コントローラも実装してしまいましょう。実装はリスト3のようになります。シンプルなコードになっています。$c->dbhでデータベースハンドルを取り出して操作を行っています。$c->req()は、Amon2::Web::Requestのインスタンスを取り出すアクセサメソッドです。Amon2::Web::RequestはPlack::Requestのラッパですが、paramメソッドをラップしていて、自動的に文字コードのデコーディング処理が実行されていることに注意してください。

リスト3 実装後のディスパッチャ
package MyApp::Web::Dispatcher;
use strict;
use warnings;

use Amon2::Web::Dispatcher::Lite;

any '/' => sub {
    my ($c) = @_;

    my @entries = @{$c->dbh->selectall_arrayref(
        q{SELECT * FROM entry ORDER BY entry_id DESC LIMIT 10},
        {Slice => {}}
    )};
    return $c->render(
        "index.tt" => {
            entries => \@entries,
        }
    );
};

post '/post' => sub {
    my ($c) = @_;

    if (my $body = $c->req->param('body')) {
        $c->dbh->insert(entry => +{
            body => $body,
        });
    }
    return $c->redirect('/');
};

1;

テンプレートの変更

最後の仕上げに、テンプレートを変更しましょう。変更すべきテンプレートはtmpl/index.ttというファイルです。これをリスト4のように変更します。Amon2ではデフォルトでText::Xslateをテンプレートエンジンとして採用しており、TTerseというシンタックスを用いています。これはTemplate-Toolkitに近い文法なので、シンプルで見やすいです。

リスト4 テンプレート
[% WRAPPER 'include/layout.tt' %]

<form method="post" action="[% uri_for('/post') %]">
    <input type="text" name="body" />
    <input type="submit" value="Send" />
</form>

<ul>
[% FOR entry IN entries %]
    <li>[% entry.entry_id %]. [% entry.body %]</li>
[% END %]
</ul>

[% END %]

柔軟なトリガ

Amon2ではSledge由来の柔軟なトリガ機構を提供しています。現在のバージョンは表1に挙げたものをサポートしています。Amon2自体を変更しなくても容易に拡張ができますし、これらのトリガを利用したプラグインの開発も容易となっています。

表1 Amon2のトリガ
名称概要
BEFORE_DISPATCHコントローラの動作前
AFTER_DISPATCHコントローラの動作後
HTML_FILTERHTMLへのフィルタ処理

トリガにコードを追加するにはMyApp::Webの中で次のように書きます。

__PACKAGE__->add_trigger(BEFORE_DISPATCH => sub {
    my $c = shift;
    ...
});

HTML_FILTERは、HTMLに対するフィルタ処理を実現します。AFTER_DISPATCHと分かれているのはUTF-8フラグの処理のためです。HTML_FILTERのタイミングではまだUTF-8フラグが立っているので文字列として扱うことができますが、AFTER_DISPATCHの時点ではエンコード済みのバイト列がわたってくるので、文字列の置換などができません。

__PACKAGE__->add_trigger(HTML_FILTER => sub {
    my ($c, $html) = @_;
    $html =~ s/ さいきろん/ さいくろん/g;
    return $html;
});

AFTER_DISPATCHの場合にはResponseオブジェクトが渡ってきますから、このオブジェクトを操作できます。

__PACKAGE__->add_trigger(AFTER_DISPATCH => sub {
    my ($c, $response) = @_;
...
});

また、トリガはクラスに対して書けるだけでなくコンテキストオブジェクトのインスタンスに対しても書けます。この場合は現在のコンテキストが終了するまでの間だけ有効となります。

sub index {
  my $c = shift;
  $c->add_trigger(AFTER_DISPATCH => sub { ... });
  ...
}

まとめ

今回は、Amon2というWebアプリケーションフレームワークについて簡単に解説しました。非常に安定しているので使いやすいと思います。ぜひお試しください。

さて、次回の執筆者はまかまか般若波羅蜜さんで、テーマは「Acmeモジュールで広がるPerlの世界」です。

おすすめ記事

記事・ニュース一覧