Practice of Programming

プログラム とか Linuxとかの話題

Catalyst::Model::DBIC::Schemaのmodelメソッドを便利にする

Catalyst::Model::DBIC::Schemaのソース
http://search.cpan.org/src/BOGDAN/Catalyst-Model-DBIC-Schema-0.21/lib/Catalyst/Model/DBIC/Schema.pm

new の後半部分。Modelクラスを動的に増やして、そこに、ACCEPT_CONTEXTを生やしている。

sub new {
    my $self = shift->NEXT::new(@_);
    
    my $class = ref($self);
    my $model_name = $class;
    $model_name =~ s/^[\w:]+::(?:Model|M):://;
    # 略
    no strict 'refs';
    foreach my $moniker ($self->schema->sources) {
        my $classname = "${class}::$moniker";
        *{"${classname}::ACCEPT_CONTEXT"} = sub {
            shift;
            shift->model($model_name)->resultset($moniker);
        }
    }

    return $self;
}

ACCEPT_CONTEXT自体は、$c->model("Hoge", @args); と呼んだときに、
あれば使われるものだけども、このメソッドには、$cと@args がわたってくる。
Catalyst::Model::DBIC::Schemaでは、@argsを使うような使い方はしないわけだが、
これを利用してやる。

sub new {
    my $self = shift->NEXT::new(@_);
    # 略
    no strict 'refs';
    foreach my $moniker ($self->schema->sources) {
        my $classname = "${class}::$moniker";
        *{"${classname}::ACCEPT_CONTEXT"} = sub {
            my ($self, $c, $method, @args) = @_;
            if (defined $method) {
                if ($method =~ s/^paged_//) {
                    # ごにょごにょ
                    return ...;
                } else {
                    return $self->model($model_name)->resultset($moniker)->$method(@args)
                }
            } else {
                return $self->model($model_name)->resultset($moniker);
            }
        }
    }

    return $self;
}

途中略しちゃってるけど、paged_ をメソッド名の先頭につけて、

 my $rs = $c->model("Hoge", paged_search => {}, {});

とかすると、$rs は、ページ分けされたものが返ってきて、$c->stash->{pager} には、
$rs->pagerが突っ込み済みとか、そんなノリにしてやると、結構使えるんでないかと思います。
というか、ずいぶん楽です。


$c->req->param('page')はページ数だとか、まぁ、なんか、お約束を作っておく必要はあるけど。決めといたほうが良いし。