Hatena::Groupcatalyst

dann@catalyst このページをアンテナに追加 RSSフィード

2008-03-22

Catalystに依存しないDBICのモデルクラス

00:04 |  Catalystに依存しないDBICのモデルクラス - dann@catalyst を含むブックマーク はてなブックマーク -  Catalystに依存しないDBICのモデルクラス - dann@catalyst  Catalystに依存しないDBICのモデルクラス - dann@catalyst のブックマークコメント

を作ってみた。

Catalystに依存しないでDBICを使うにはどうすればいいんだろうとこの連休は考えていた。Schemaってやつが情報を知りすぎていて、どうもクラスに分割しにくい。全部のテーブル情報知っちゃってるからで、どうしたもんかなぁと思っていた。

resultsetごとにクラスが分割できるようにベースクラスを作ればいいんだと思った。ベースクラスでやってるのはSchema取得。resultsetを取得して、そのresultsetに対して処理ができるようにするということ。

モデルのクラスからは、SchemaやResultsetが直接みえないようになる。けど、DBICのメソッドは直接触りたいから、AUTOLOADで処理をディスパッチする。という感じ。

Logicのクラスで$schema->resultset('Feeds')->search() とかはしたくないなぁと思って、綺麗に扱えないかっていうだけのことなんだけれど。多くの処理は、MangoのProviderからのパクリですが... ただ、Mangoはメソッドをラップして、Domainモデルを作ろうとしているんだけれど、これは自分には必要ないので、AUTOLOADでresultsetに全部ディスパッチするようにしたというのが違いかな。

モデルのベースクラス(今のところ特に何もしてない)

package MyApp::Base::Model;
use strict;
use warnings;

BEGIN {
    use base qw/Class::Accessor::Grouped/;
};

sub new {
    my ($class, $args) = @_;
    my $self = bless {}, $class;

    $self->setup($args);

    return $self;
};

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

    if (ref $args eq 'HASH') {
        map {
            if ($self->can($_)) {
                $self->$_($args->{$_})
            } else {
                $self->{$_}  = $args->{$_};
            }
        } keys %{$args};
    };

    return;
};

1;

Catalystに依存しないDBIC用のモデルのベースクラス

package MyApp::Base::Model::DBIC;
use MyApp::ConfigLoader;
use strict;
use warnings;
BEGIN {
    use base qw/MyApp::Base::Model/;
    use UNIVERSAL;
    use MyApp::Exception qw/:try/;

    __PACKAGE__->mk_group_accessors('component_class', qw/schema_class/);
    __PACKAGE__->mk_group_accessors('inherited', qw/
        config
        source_name
        connection_info
        _resultset
        _schema
    /);
};
__PACKAGE__->schema_class('MyApp::Schema');

sub new {
    my $class = shift;
    my $self  = $class->SUPER::new(@_);
    $self->setup_config;
    $self->setup_connection_info;
    return $self;
}

sub setup_config {
    # FIXME
    # Catalystで使うときは、configloaderがセットされた状態にする。
    my ($self) = @_;
    unless($self->config) {
        my $config = MyApp::ConfigLoader->new->config;
        $self->config($config);
    }
}

sub setup_connection_info {
    my ($self) = @_;
    $self->connection_info(
        $self->config->{'Model::DBIC'}{'connect_info'}
    );
}

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

    if (defined $resultset) {
        $self->_resultset($resultset);
    } elsif (!$self->_resultset) {
        if (!$self->source_name) {
            MyApp::Exception->throw('SCHEMA_SOURCE_NOT_SPECIFIED');
        };

        try {
            $self->_resultset($self->schema->resultset($self->source_name));
        } except {
            MyApp::Exception->throw('SCHEMA_SOURCE_NOT_FOUND', $self->source_name);
        };
    };

    return $self->_resultset;
};

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

    if ($schema) {
        $self->_schema($schema);
    } elsif (!$self->_schema) {
        if (!$self->schema_class) {
            MyApp::Exception->throw('SCHEMA_CLASS_NOT_SPECIFIED');
        };
        $self->_schema(
            $self->schema_class->connect(@{$self->connection_info || []})
        );
    };

    return $self->_schema;
};

sub DESTROY {}

sub AUTOLOAD {
    my $self = shift;
    my $method = our $AUTOLOAD;
    $method =~ s/.*:://o;
    warn $method;
    $self->resultset->$method(@_);
}

1;

実際のモデルのクラス

package MyApp::Model::Feeds;
use base qw/MyApp::Base::Model::DBIC/;

__PACKAGE__->source_name('Feeds');

1;

使用方法

    my $feed = MyApp::Model::Feeds->new;
    $feed->update_or_create(
        {   feedlink => 'http://hoge.com/',
            link     => 'hoge.com',
            title    => 'hogehoge'
        }
    );

# まじめにここの仕組みは考えたいから、これじゃ使えないよ!とか突っ込み希望です。

改善案

AUTOLOADを1回だけ呼ぶようにする

http://d.hatena.ne.jp/ysano2005/20051229/1135870740

vkgtaro++

全部Resultsetにdispatchするんだったら、newする段階でresultset返しちゃえばいいんじゃないかというtomyheroさんからの意見。ごもっとも!tModelクラスにロジックを書くという案を最初考えていたから、Resultsetにディスパッチしてるんだけど、実はそれだと自動生成が面倒になるので、それもいいかもしれない!

トラックバック - http://catalyst.g.hatena.ne.jp/dann/20080322