FormValidator::Liteをwrapして使ってみる。

そのままでも充分使えそうですが、痒いところに手が届くようにしてみました。
ユーザーのプロフィールを入力するフォームをバリデートする感じで下記を書いてみました。

まずはerror_messageのymlを用意。

message:
  name.not_null: ''
param:
  name: 名前
  age: 年齢
function:
  not_null: "[_1]を入力してね"
  int: "[_1]は数値で入力してね"

サイト内に他のフォームがある場合は、myapp/error_message/*.ymlを用意する感じで。

で、use FormValidator::LiteなMyApp::FormValidatorってのを用意。

package MyApp::FormValidator;

use Object::Simple -base;
hash [qw/form message/];

use FormValidator::Lite;
use Path::Class;
use YAML;

sub new {
    my $c = shift;
    my $self = $c->SUPER::new(@_);

    # ymlを全部読み込み
    my $message = {};
    my $dir = dir('myapp/error_message');
    while ( my $d = $dir->next ) {
        my $path = $d;
        if ( $d =~ /(\w+?)\.yml$/ ) {
            my $yml = YAML::LoadFile( $d );
            $message->{ $1 } = $yml;
        }
    }
    $self->message($message);

    return $self;
}

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

    my $v = FormValidator::Lite->new( $args->{'req'} );
    my $yml = $self->yml->{ $args->{'action'} };
    $v->set_message_data( $yml );

    my $res = $v->check( @{ $args->{'check'} } );

    # この辺はお好みでどうぞ(詳しくは下に)
    my $message = {};
    if ( $v->has_error ) {
        for my $p ( keys %{ $yml->{'param'} } ) {
            next unless ( exists $v->get_error_messages_from_param( $p )->[0] );
            $message->{ $p } = $v->get_error_messages_from_param( $p )->[0];
        }

        return {
            is_ok => 0,
            message => $message,
        }
    }

    return { is_ok => 1 };
}

1;

error_messageをhashに入れなおしてるのは、それぞれのフォームにエラーメッセージ(名前入力フォームには名前のエラーみたいな感じ)を表示する用です。
上とか下にまとめて、ドーンと全部メッセージを出す場合はいらないです。

で、上をuseしてみる。

package MyApp::User;

use CGI;
use MyApp::FormValidator;

my $q = CGI->new();
my $v = MyApp::FormValidator->new();

my $res = $v->validator({
    req => $q,
    action => 'user', # user.ymlを使う
    check => [
        name => [qw/NOT_NULL/],
        age => [qw/INT/]
    ]
});
unless ( $res->{'is_ok'} ) {
    say $res->{'message'}->{'name'};
    say $res->{'message'}->{'age'};
    return 1;
}

say 'ok!!';

大体こんな感じで。

これ良く考えたら、Object::Simpleじゃなくて、Class::Accessor::Liteにすれば良かった気がしないでもない。
(FormValidator::Liteの中でClass::Accessor::Lite使ってるので・・・)