エラー標準化&ロジック共有化モジュール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 等認証部分が特に汎用的に作りやすいきがします。