Catalystでクエリを扱うための便利メソッド

今までクエリ扱うのにCGI.pmをラップした独自モジュールを使ってたんですが、いくつか便利なメソッドがあったのでそれをCatalystから扱えるようにしてみました。

プラグイン名はとりあえずCatalyst::Plugin::Request::Utilとでも。

package Catalyst::Plugin::Request::Util;

use warnings;
use strict;
use NEXT;
use Catalyst::Request;

our $VERSION = '0.01';

package Catalyst::Request;

sub value { scalar shift->param(shift) }

sub value_list {
    my $self = shift;
    map { scalar $self->param($_) } @_;
}

sub exists { defined shift->value(shift) }

sub query {
    my $self = shift;
    my %ret;
    for( @_ ){
        my @tmp  = $self->param($_);
        $ret{$_} = @tmp > 1 ? \@tmp   :
                   @tmp     ? $tmp[0] : undef;
        delete $ret{$_} unless defined $ret{$_};
    }
    wantarray ? %ret : \%ret;
}

sub regex_query {
    my $self  = shift;
    my $regex = shift;
    my %ret;
    for( $self->param ){
        next unless /$regex/;
        my $key = defined($1) ? $1 : $_;
        my @tmp  = $self->param($_);
        $ret{$key} = @tmp > 1 ? \@tmp   :
                     @tmp     ? $tmp[0] : undef;
        delete $ret{$key} unless defined $ret{$key};
    }
    wantarray ? %ret : \%ret;
}

1;

追加したメソッドの数は5個。

ざっと使い方の説明をします。

まずはvalueメソッド。

単純にparamの戻り値をscalarしてるだけなんですがこれが便利なんです。

paramってコンテキストによって動作が変わるのでよく下記のような間違いを犯してしまう。

 sub hoge {
     my $param1 = shift;
     my $param2 = shift;
 }

 sub test : Local {
     my ( $self,$c ) = @_;
     
     # クエリから渡された値をhogeに渡す。
     hoge( $c->req->param('param1') , $c->req->param('param2') );
 }

これ、一見うまくいきそうですが、param1が複数個渡されてた場合、つまり「test?param1=a¶m1=b」みたいなアクセスがあった場合におかしくなります。

だからこういう処理をする場合、ちゃんとコンテキストを指定してやらないといけないわけです。

 # scalarを使う
 hoge( scalar $c->req->param('param1') , scalar $c->req->param('param2') );

このscalarを付けるのがメンドクサイのと、よく付け忘れてしまうのでvalueメソッドですっきり書けるようになるわけです。

 # valueメソッドですっきり綺麗
 hoge( $c->req->value('param1') , $c->req->value('param2') );

次にvalue_list。

これは引数に指定した複数のパラメータをその順番通りの配列で返してくれるだけのものです。つまり、

 # これら二つの処理は同じ処理
 hoge( $c->req->value('param1') , $c->req->value('param2') );
 hoge( $c->req->value_list('param1','param2') );

ということになります。これも短く書けて便利です。

で次がexists。

これはパラメータが渡されているかどうかチェックするだけのものです。

 sub test : Local {
     my ( $self,$c ) = @_;
     
     if ( $c->req->exists('hoge') ) {
         # 以下全部真となる
         # test?hoge=
         # test?hoge=0
         # test?hoge=aaa
     }
 }

お次はquery。

これは引数に渡された複数のパラメータ名をハッシュ形式で返します。

説明するより例を見たほうが早いと思うので。

 sub test : Local {
     my ( $self,$c ) = @_;
     
     my $query = $c->req->query('hoge','muge');
     
     # test?hoge=a&muge=b の場合
     # $query = {
     #     hoge => 'a',
     #     muge => 'b',
     # }

     # test?hoge=a&muge= の場合
     # $query = {
     #     hoge => 'a',
     #     muge => '',
     # }

     # test?hoge=a&muge=b&muge=c の場合
     # $query = {
     #     hoge => 'a',
     #     muge => ['b','c'],
     # }

     # test?hoge=a の場合
     # $query = {
     #     hoge => 'a',
     # }

 }

となります。

最後にregex_query。

これはさっきのqueryとほぼ同じで正規表現でパラメータ名を指定できます。

 sub test : Local {
     my ( $self,$c ) = @_;
     
     my $query = $c->req->regex_query(qr/^hoge_/);
     
     # test?hoge_a=1&hoge_b=2&hoge=3 の場合
     # $query = {
     #     hoge_a => '1',
     #     hoge_b => '2',
     # }

 }

正規表現を指定する際に、括弧を使えば後方参照を利用してキー名を取得できます。

 sub test : Local {
     my ( $self,$c ) = @_;
     
     my $query = $c->req->regex_query(qr/^hoge_(.*)$/); # 後方参照
     
     # test?hoge_a=1&hoge_b=2&hoge=3 の場合
     # $query = {
     #     a => '1',
     #     b => '2',
     # }

 }

このように括弧でくくった部分だけがキー名になり取得することができるわけです。

ざっくり説明終わりっと。

ちなみにこのプラグインではCatalyst::Requestパッケージに直接アクセスしてメソッド定義したんだけどこんなんでいいのかなぁ?

他のプラグインとか色々見てるとみんなそうしてるんで僕もそうしたんだけどもちょっと微妙なキガス。

でも楽だしまぁいいかっ。