エラー標準化&ロジック共有化モジュールAplon
最終更新日 : 2011-02-23 23:45:19
目的
- エラー処理の標準化を行う
- ロジックを共有しやすいようにする
概要
Webのコントローラに直接ロジックを書くと、使い回しがしづらい&Web依存(リクエスト/レスポンス等処理)が発生してしまうという問題の対応として、ロジック周りを外に出すという設計が一般的に行われます。Aplonはこのロジック部分の実装の標準化を行いつつ、実装の手助けを行い、また、作成したロジックを再>利用することを可能にします。
チュウトリアル
基本
ロジック関数を作る
ユーザIDを渡すとユーザのデータが取得できる関数を試しに作ってみます。
package Aplon::Model::User;
use Mouse;
extends 'Aplon';
sub lookup {
my $self = shift;
my $id = shift;
if($id =~ /^[0-9]+$/ ){
if($self->aplon_user('ADMIN_USER') ){
return {
name => 'tomohiro',
password => '1111',
};
}else {
return {
name => 'tomohiro',
};
}
}
else {
$self->abort_with('not_found');
}
}
__PACKAGE__->meta->make_immutable();
no Mouse;
1;
ロジック関数を実行する
my $model = Aplon::Model::User->new;
eval {
my $user = $model->lookup( 32 );
};
if( my $error_obj = $@){
# エラー処理。
print Dumper $error_obj->error_keys;
}
利用ユーザで処理を変更する
aplon_user*1で利用ユーザを変更することにより、たとえばadminページではstatus = 0のデータを取得できる等の切り分けを簡単に行うことができます。
my $model = Aplon::Model::User->new({ aplon_user => 'ADMIN_USER' });
eval {
my $user = $model->lookup( 32 ); # passwordも取得できる
};
if( my $error_obj = $@){
# エラー処理
print Dumper $error_obj->error_keys;
};
Data::FormValidatorを利用する
Validateモジュール作成(Aplon::Validator::Data::Form::Validator)
Aplon::Validator::Data::Form::Validatorを利用することにより、簡単に Data::Form::Validatorと連動することができます。Aplon::Validator::Data::Form::Validatorだけではconstraintsの設定がありませんので、以下のように拡張する必要があります。
package MyApp::Validator::DFV;
use Mouse::Role;
with 'Aplon::Validator::Data::Form::Validator';
use Data::FormValidator::Constraints qw(:closures);
sub DFV_constraint_methods {
my $self = shift;
return +{
status => qr/^[01]$/,
name => [
FV_max_length(10),
qr/^[a-zA-Z0-9_]+$/,
qr/^[a-zA-Z_]+$/, # multi invalid test
],
}
}
sub DFV_constraint_method_regexp_map {
my $self = shift;
return +{
qr/_id$/ => qr/^[0-9]+$/,
}
}
1;
Modelモジュールで利用する
package MyApp::Model::User;
use Mouse;
extends 'Aplon';
with 'MyApp::Validator::DFV';
sub profiles {
my $self = shift;
return {
get_name => {
required => [qw/name/],
optional => [qw/status/],
}
}
}
sub get_name {
my $self = shift;
my $args = shift;
my $results = $self->assert_with($args);
if($results->valid->{status}){
return $results->valid->{name};
}
else {
$self->abort_with($results,'not_found');
}
}
__PACKAGE__->meta->make_immutable();
no Mouse;
1;
実行する
eval {
$model->get_name({ name => 'tomohiro.teranishi', status => 1 })
};
if(my $error_obj = $@ ){
# do error thing with $error_obj
}
同じ用な感じでAplon::Validator::FormValidator::LazyWay を利用することができます。さらに詳しくは https://github.com/tomyhero/p5-Aplon/tree/master/t 配下を見ていただければと。
エラーオブジェクトについて
特に複雑なものではなく、以下の情報がエラーがあった際に格納される感じです。
エラーメッセージ等は、error_keysから作成することができると思います。例えばこんな感じです。
package Aplon::Error;
use Mouse;
has 'code' => ( is => 'rw' , default => 'ERROR' );
has 'missing' => (is => 'rw', default => sub { [] } );
has 'invalid' => (is => 'rw', default => sub { {} } );
has 'valid' => (is => 'rw', default => sub { {} } );
has 'custom_invalid' => (is => 'rw', default => sub { [] } );
has 'error_keys' => ( is => 'rw' , default => sub { [] } );
__PACKAGE__->meta->make_immutable();
no Mouse;
1;
CRUDを実装する
実装してないです。lookup/search/remove/add/update 等をMixInするだけで利用できる感じの実装とかです。
全員に汎用的なのを作るのは難しいので、Project毎や、ORM毎等に作るかたちになります。
汎用的なロジックを作る
作ってないんですが、Aplon::Model::Twitter::OAuth, Aplon::Model::OpenID 等認証部分が特に汎用的に作りやすいきがします。