« ciscolet | Home | Moment / Sotte Bosse »

[Catalyst]   Catalyst::Model::Adaptorを使ってみた

Catalyst::Model::Adaptor - use a plain class as a Catalyst model

要はどんなクラスでもCatalystのモデルにしてくれるクラスです。

たとえばこんなクラスを作って

lib/MyApp/DateTime.pm
package MyApp::DateTime;

use strict;
use warnings;

use base qw/DateTime/;
use DateTime::Format::W3CDTF;

sub now {
    my ($class, $args) = @_;

    $args->{time_zone} = 'local' unless $args->{time_zone};
    return $class->SUPER::now(%$args);
}

sub parse {
    my ( $class, $str ) = @_;

    my $dt = DateTime::Format::W3CDTF->parse_datetime($str);
    bless $dt, $class;
}

sub format {
    my $self = shift;

    return DateTime::Format::W3CDTF->format_datetime($self);
}

で、ヘルパーを使うと

script/myapp_create.pl model DateTime Adaptor MyApp::DateTime now 

こんなクラスを作ってくれます。

lib/MyApp/Model/DateTime.pm
MyApp::Model::DateTime

package Test::Model::DateTime;
use strict;
use warnings;
use base 'Catalyst::Model::Adaptor';

__PACKAGE__->config(
    class       => 'Test::DateTime',
    constructor => 'now',
);

1;

ヘルパーの使い方は

script/myapp_create.pl model [Modelクラスの名前] Adaptor [使うクラス名] [コンストラクタ名]

みたいな感じ

で、コントローラにこんな感じのを書いて

lib/MyApp/Controller/Root.pm

-snip-

sub now : Local {
    my ($self, $c) = @_;

    my $model = $c->model('DateTime');
    $c->res->body($model->format);
}

-snip-

サーバーをあげて/nowにアクセスすると現在の時間をW3CDTFな書式で表示してくれます。
便利!

・・・ですがリロードしても時間が変わりません。
で、M::DateTimeを変更します。

lib/MyApp/Model/DateTime.pm
MyApp::Model::DateTime

- snip -

use base 'Catalyst::Model::Factory';

- snip -

で、あげなおしてリロードしたらちゃんと現在の日時を返してくれます。

Catalyst::Model::Adaptorのパッケージには

Catalyst::Model::Adaptor - アプリケーションの起動時にインスタンスを生成
Catalyst::Model::Factory::PerRequest - リクエストごとにインスタンスを生成
Catalyst::Model::Factory - $c->model()で呼ばれるたびにインスタンスを生成

が入ってるのでそれぞれの用途で使い分けるといいです。

また、コンストラクタの引数を設定ファイルに指定する場合は

---
name: Test
Model::DateTime:
  args:
    time_zone: UTC

な感じでargs:の下に書くとよろし。

ただし、注意しなければいけないのはC::M::Adaptorからクラスのコンストラクタに渡る引数はハッシュリファレンスになります。今回はクラスのほうでDateTimeクラスに渡すときに変換していますが、C::M::Adaptorのprepare_argumentsとmangle_argumentsをオーバーライドすることで行うこともできます。

MyApp::DateTimeからnow()を削って、MyApp::Model::DateTimeに

sub prepare_arguments {
    my ( $self, $app ) = @_;

    my $args = $self->{args};
    $args->{time_zone} =  'local' unless $args->{time_zone};
    return $args;
}

sub mangle_arguments {
    my ( $self, $args ) = @_;

    return %$args;
}

を追加する感じ。

ドキュメントにありますが要は内部的に

my $args = $self->prepare_arguments($app);
$adapted_class->$constructor($self->mangle_args($args));

みたいな処理をしてアプリケーションからクラスのコンストラクタに渡してるのでそれぞれフックしてやる感じです。

Trackbacks:

このエントリーのトラックバックURL:

この一覧は、次のエントリーを参照しています: Catalyst::Model::Adaptorを使ってみた:

[Perl][Catalyst]Catalyst::Model::Adapterを使ってみたよ from urapicoの日記(メモ的に)
CatalystでDBを普通のRDBとかを使わずにYAMLファイルをDBみたいな感じにしたいと思って、Adapterを使ってモデルクラスを作ってみました...

コメントを投稿





Profile

Information

あわせて読みたい