DBIx::Class::Validation
DBIx::Class::Validation - Validate all data before submitting to your database. - metacpan.org
モデル層でValidationするモジュールなんだけど、単純にCatalystで使ってみたらイマイチだったのでメモ。
イマイチというのはコントローラが思いのほか汚くなってしまうということと、確認画面があるようなフォームだとモデル層に行く前(insert/updateする前、確認用アクション)でValidationすることになるので単純に使えないということです。また、特にtxn_doとか使うとevalばっかになって嫌な感じです。
sub create_save : Path('create/save') { my ($self, $c) = @_; if ($c->session->{entry}) { eval { $c->model('DBIC')->schema->txn_do(sub{ eval { $c->model('DBIC::Entry')->create({ %{$c->session->{entry}}, user_id => $c->user->obj->id, }); }; if ($@) { $c->stash->{result} = $@; die "validation error"; } }); }; if ($@) { $c->stash->{template} = 'entry/create.tt'; return; } $c->session_expire_key(entry => -1); } $c->res->redirect($c->uri_for('/entry')); }
もともと確認画面を表示してからここに来るフローだったので、セッションに格納したデータを使ってますがこの話には関係ありません。
また、スキーマクラスではこんな感じにvalidationを設定しています。
autoをセットした場合はinsert/updateの際に自動でvalidateを行い、エラーの場合はFormValidator::Simple::Resultsを例外として投げます(croakします)。
__PACKAGE__->validation( module => 'FormValidator::Simple', profile => [ title => ['NOT_BLANK', ['JLENGTH', 0, 255]], body => ['NOT_BLANK', ['JLENGTH', 0, 2000]], ], filters => 0, auto => 1, );
txn_doの中と外でevalを使っていますが、txn_doの外だとvalidationのresultを$@経由で受け取れなかったためです(なぜか1になっていた)。
-
- -
さて、よくよく追っていくとこのモジュールはHandelで使うために作られたようなモジュールみたいなのでこういうことになるのかなと思いました。HandelではHandel::Storage::DBICでValidationクラスとしてHandel::Components::Validation(DBIx::Class::Validationのサブクラス)を使うようになっています。そしてDBIx::Class::Schemaのexception_action()を使用してHandel独自の例外クラスを投げるという仕組みのようです。コントローラから実際のモデルクラスまでが遠く、その間のラップクラスがうまいことやっているおかげでコントローラからキレイに使えるようになっているのではないかなーと想像しています(実際にどうかは使ったことがないのでわかりませんが)。
-
- -