Catalyst::Plugin::XSendFile
lightyのX-SendfileをCatalystから使うプラグインをつくった。
$c->res->sendfile("/path/to/file");
って感じで使えます。同じインタフェースでCatalystテストサーバーの時でも動くようになってます。
miyagawaさんの話だとperlbalでも同じようなことが出来るとのこと(もっと高機能)。でさらにそれにmogilefsを組み合わせるとかなりスケーラビリティが高そうな感じ。
ちょっと見てみるべきかなぁ。
Action attribute
Catalyst 5.70 の dev リリースでサポートされた Action attribute 良いね。
http://search.cpan.org/~mramberg/Catalyst-Action-RenderView-0.01/lib/Catalyst/Action/RenderView.pm
こんなんとか簡単に作れる。cool。
sub foo : Action('+Foo::Bar')
は
sub foo : MyAction('Foo::Bar')
と等価。
マルチ language なアプリを作る練習もかねて、ちょっとしたサイトつくりはじめたんだけど、
msgid "Logged in as %1"
msgstr "%1 としてログインしています"
こういうのが化ける。%1
とかはいってないのはいける。Unicodeフラグっぽい化けかたなので、MyApp.pm に
sub localize {
my $c = shift;
my $text = shift;
my $args = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
for my $arg (@$args) {
utf8::decode($arg);# unless utf8::is_utf8($arg);
}
$c->NEXT::localize( $text, $args );
}
とか書いてみたら直ったよ。しかし、is_utf8
のところコメント外すとうごかねーよ、なにこれ。
$args
には is_utf8
は真だけど、perl utf8 じゃないのがはいってる?何かが悪さをしておる。
Unicode プラグインと併用してるのがまずいのかもしれん。
Schema::Loader with Catalyst
Catalyst::Model::DBIC::Schema を使う。
この Model は大きく3つの使いかたがある。
- 単純に既に存在する Schema クラスを使用する
- Schema::Loader で既存の DB から Schema クラスを生成し、それを使用する
- Schema::Loader で既存の DB から Schema::Loader クラスを生成し、それを利用する。
1 はまず Schema クラスをどこかに作ってあり(My::Schemaと仮定する)、それをそのまま Catalyst::Model として利用する。
./script/myapp_create.pl model DBIC DBIC::Schema My::Schema
で、MyApp::Model::DBIC が作成される。この My::Schema に connection なんかが定義されていてそれを使う場合はこのままでOK。
別の接続先を使う場合なんかは MyApp::Model::DBIC の設定で connect_info を書いておけばそっちが使われる。ヘルパーの最後に
./script/myapp_create.pl model DBIC DBIC::Schema My::Schema dbi:SQLite:/path/to/foo.db
とかしてもOK。
で、これでアプリ内から Schema クラスを使える。で、この場合で My::Schema::Table を使うには $c->model('DBIC::Table')->search
とかとする。ここがわかりにくいのかもしれない。
2 は 1 と同じだが、ヘルパーを叩くときに既存DBを元にSchemaクラスを生成する。
./script/myapp_create.pl model DBIC DBIC::Schema My::Schema create=static dbi:SQLite:myapp.db
こんな感じで、ヘルパーを叩いたときに、myapp.db のテーブル定義をもとに My::Schema(::*) クラスが自動生成される。後の使いかたは同じ。
3 は Schema クラスではなく、Schema::Loader クラスを生成し、Catalystアプリが起動するたびにDBのテーブル定義を見て動的にSchemaクラスを生成する。Catalyst::Model::CDBI みたいな感じ。
これを使うには
./script/myapp_create.pl model DBIC DBIC::Schema My::Schema create=dynamic dbi:SQLite:myapp.db
で、My::Schema という Schema::Loader クラスが生成され、それが使われる。
Catalystアプリからの使いかたはすべて1と同じ。
My::Schema::* をよぶのに、$c->model('DBIC::*')
を呼ぶというのがわかりずらいのかも。
あと、Schema::Loader を使う場合、テーブル定義以外の、リレーションの設定とかインフレーションとかの設定を書くために、My::Schema::Table を書くかもしれないが、CDBI::Loader と違いそれらはデフォルトでは読み込まれないから注意が必要。
それらをロードするためには、My::Schema に __PACKAGE__->load_classes;
を付け加える必要がある。
たしかになんかわかりにくいかも。かなぁ。
- Schema based な DBIC の使いかたの例: DBIx::Class::Manual::Example
- C::M::Schema::Loader: Catalyst::Model::Schema::Loader
- とそのヘルパー: Catalyst::Helper::Model::Schema::Loader
とかの pod を見るといいかも。
Plugin::Flavour
URLの最初のパスをflavourに使うっていうやつを別モジュールにきりわけようかとおもうんだけど、だめかなぁ。
誰か使ってたりすんのかなぁ。
$c が必要な場合 prepare ハンドラは使うべきではない
代りに prepare_*
を使え。
そもそも NEXT のチェーンで
sub prepare {
my $class = shift;
my $c = $class->NEXT::prepare(@_);
...
}
とか、NEXT 呼んだ後に処理を書くべきじゃないと思う。こうすると実行される順番があべこべになってしまう。
こうする必要があるのは prepare は $c
ではなくクラス名を渡されるようになっているため。
prepare_*
は $c がわたされる。
SYNOPSIS of Plugin::FormValidator::Simple::Auto
use Catalyst qw/ FormValidator::Simple FormValidator::Simple::Auto /;
__PACKAGE__->config(
validator => {
messages => 'messages.yml',
profiles => 'profiles.yml',
# and other FormValidator::Simple config
},
);
# profiles.yml
action1:
param1:
- NOT_BLANK
- ASCII
- [ 'LENGTH', 4, 10 ]
param2:
- NOT_BLANK
# then your action
sub action1 : Global {
my ($self, $c) = @_;
# $c->form($profile) already executed!
unless ($c->form->has_error) {
...
}
}
とか言うのを作ろうかと。
牧さんのパクリ。
del.icio.us/url/f140e1ad9d58fa4f5b2ee0b55b9002db
Catalyst::Authentication と NEXT.pm. NEXTでのMixinだとplugin内にメソッド定義しにくいため
Auth::Credential::*
,A::Store::*
な名前空間がある。
これはちょっと違うので補足。
それら二つの名前空間は単にいろいろな認証系に対応するためのもので、NEXTのために名前空間をわけているわけではないです。
実装的にも Credential::*
も Store::*
も Authentication プラグインを利用してはいますが、それら自体は普通の Catalyst プラグインで、
use Catalyst qw(
Authentication
Authentication::Credential::Password
Authentication::Store::DBIC
);
などのようにロードします。
なのでそれぞれが、
NEXTでのMixinだとplugin内にメソッド定義しにくい
ということはいえます。
Catalyst の認証系
これはちょっとなぁ。コメントしようと思ったけど途中まで書いて長くなったのでここに書いておく。
まず、Authentication::Credential::*
と Authentication::Store::*
はどちらも Authentication
プラグインを利用する認証プラグインのための名前空間。
なので、上記プラグインは Credential とつけるのはいくない。
Authentication プラグインは Catalyst プラグインだけど、それ自体が認証プラグイン用のフレームワークみたいになっていて、ユーザー(プログラマ)はさまざまなバックエンドプラグインを共通のインタフェースで使用することができるようになっている。
んで、上記プラグイン、名前をかえればいいんじゃね。とかおもったけどよくみたらこれ、$c->login
とかよんでる。
んでloginはプラグイン内になくて、トップレベルのアクションに login : Local
とか書いてる。これ、MyApp.pm にlogin定義してないと動かないんじゃね。
Authentication プラグインのコードが読みにくいということも問題かなぁ。NEXT を使うMixinのプラグイン機構はそのプラグイン内にメソッドを定義しまくれない(すべて$c
の関数になってしまうから)ため、複雑な処理をしようとすると別名前空間を使う必要があるので実装がむずかしい。
それプラス、作者が nothingmuch。この人のコードは基本読みにくいw
でも、Authentication プラグインをつかったはてな認証プラグインはすでにあるので、今からつくるなら Authentication プラグインを使わないもののほうがいいのかな。