Amon2で簡易Modelを作る
Amon2
でModel
を実装するにはどうすればいいか試行錯誤してみました。
flavor
はBasic
を想定しています。
内容
まずはググる
Amon2 Model
でググって以下のサイトを見つけました。
すでにPlugin
として公開されている方がいらっしゃいました。
ならこれを使えばすぐにModel
を実装できるのでは?
ということで試してみました。
とりあえず簡易でいい
「 Amon2::Plugin::Model というのを書いて使っているので公開してみた」を見てもらえればなのですが、試してみて何となくModelクラス
が冗長な感じがしてしまいました。
もっと簡単な記述でささっと使えないものかなーと思ったので、上記の2サイトを参考にしながら実装してみました。
実装
まずはどんな感じで使いたいかを考えてみます。
実装要件は以下。
Modelクラス
は最低限の記述でWeb
側からの呼び出しは参考サイトみたいにO/Rマッパー「Teng」
を使用- 今回は
DB
としてmysql
を想定
まずはconfigファイルを編集。
この情報を元にDB
にアクセスします。
return { DB => [ 'DBI:mysql:[hostname]:[servername]:[portnumber]', '[username]', '[password]', ], }
次にlib/MyApp.pm
を編集していきます。
まずはdbメソッド
を編集してDB
への接続とTeng
を利用できるようにします。
sub db { my $c = shift; if (!exists $c->{db}) { my $conf = $c->config->{DB} or die "Missing configuration about DB"; $c->{db} = Teng->new( connect_info => $conf, schema_class => "MyApp::DB::Schema", ); } $c->{db}; }
続いてmodelメソッド
を追加。
これで$c->model('Foo')
とかやるとFooモデル
を呼び出せます。
sub model { my ($c, $model_name) = @_; my $module_name = 'MyApp::Model::' . $model_name; eval "require $module_name"; return $module_name->new; }
次はModel
部分を作っていきます。
lib/MyApp/Model.pm
を作って、以下のようにします。
package MyApp::Model; use strict; use warnings; use utf8; use parent qw/MyApp/; sub new { shift } sub c { MyApp->context } 1;
後はlib/MyApp/Model/
以下にModelクラス
を必要な分だけドンドン作っていって、MyApp::Model
を継承していけば、OKです。
まずは1テーブルに対して1モデル作っていけば良いのではないかと思います。
利用方法
例えばUserモデル
としてlib/MyApp/Model/User.pm
は以下のように実装します。
package MyApp::Model::User; use strict; use warnings; use utf8; use parent qw/MyApp::Model/; sub lookup_by_id { my ($class, $id) = @_; return $class->c->db->single('user', +{ id => $id }); } 1;
Web
側では以下のように呼び出して使います。
package MyApp::Web::Dispatcher; use strict; use warnings; use utf8; use Amon2::Web::Dispatcher::RouterBoom; any '/' => sub { my ($c) = @_; my $user = $c->model('User')->lookup_by_id(1); return $c->render('index.tx', { name => $user->name }); }; 1;
最後に
これで簡易ではあるものの、Model実装ができました。
validationやらmodelメソッドの中身とか突っ込みどころ満載かとは思いますが、分かりやすさ(自分に対して)を重視しながらだとこんな感じに落ち着きました。
これはマズいってところとかあれば突っ込みお願い致します。
追記 (2014/07/13)
@pchatsuさんからご指摘をいただきました。
ModelがMyAppを継承するのはオブジェクト指向的にどうなのか。ということで、継承を止めてAmon2::Declare
を使用することにしました。
package MyApp::Model; use strict; use warnings; use utf8; use Amon2::Declare; sub new { shift; } sub db { c->db; } 1;
そして、Userモデル
の実装は以下のようになります。
package MyApp::Model::User; use strict; use warnings; use utf8; use parent qw/MyApp::Model/; sub lookup_by_id { my ($class, $id) = @_; return $class->db->single('user', +{ id => $id }); } 1;
一つ気をつけないと行けないのは、local context mode
が有効になっている場合はうまく動作しません。amon2-setupしたままだと有効になっているので、lib/MyApp.pm
の以下を消しておく必要があります。
... # Enable project local mode. __PACKAGE__->make_local_context(); ...