エラー標準化&ロジック共有化モジュールAplon

最終更新日 : 2011-02-23 23:45:19



目的


  • エラー処理の標準化を行う
  • ロジックを共有しやすいようにする

概要


Webのコントローラに直接ロジックを書くと、使い回しがしづらい&Web依存(リクエスト/レスポンス等処理)が発生してしまうという問題の対応として、ロジック周りを外に出すという設計が一般的に行われます。Aplonはこのロジック部分の実装の標準化を行いつつ、実装の手助けを行い、また、作成したロジックを再>利用することを可能にします。

ソース


https://github.com/tomyhero/p5-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 等認証部分が特に汎用的に作りやすいきがします。
  • カテゴリ:
  • Tech