HTML::FormFuではYAML形式とかでフォームを指定できるのがとってもイイ!のだが、これはこれでデータベースに入ってるリストをプルダウンメニューとして表示したい時とかに困る。特にCatalyst::Controller::HTML::FormFuを使って、FormConfigとかでキレイに組み込む事ができるのにコードを書かなくちゃいけないなんて・・・ということでCatalystではModelが使えるのに着目して、FormFu Modelを作って、Data::Visitorで値を動的に変更する仕組みにしてみた。
以下のコードを使っておけば、
- type: select
options:
- group: dynamic.foo.values
みたいな感じで、dynamicで指定された内容が置き換えられるので、好きな値を動的に吐き出せばいい。結構重宝してる。
# 前提:HTML::FormFuを使える。Catalyst::Plugin::Cacheとかでcacheが使える
# Data::Visitorが使える。package MyApp::Controller::Foo;
use base qw(Catalyst::Controller::HTML::FormFu);sub foo : FormMethod('form_config') { }
sub form_config {
my ($self, $c) = @_;
return $c->model('FormFu')->form_config('path/to/config.yml');
}package MyApp::Model::FormFu;
use base qw(Catalyst::Model);
use Data::Visitor::Callback;
use YAML::Syck qw(LoadFile);
__PACKAGE__->mk_accessors($_) for qw(context);sub ACCEPT_CONTEXT
{
my ($self, $c) = @_;
$self->context($c);
$self;
}sub form_config
{
my $self = shift;
my $file = shift;
my $c = $self->context();
my $cache = $c->cache(backend => 'parts');
my $config = $cache->get("model.formfu.form_config.$file");
if ($config) {
return $config;
}
$config = $self->load_config_from_file($file);
$cache->set("model.formfu.form_config.$file", $config);
return $config;
}sub load_config_from_file
{
my $self = shift;
my $file = shift;
my $c = $self->context;
my $path = $c->path_to(qw(root formfu config), $file);my $config = LoadFile($path->stringify);
my $re = qr{
^
dynamic\.([\w_.-]+)
}x;
my $v = Data::Visitor::Callback->new(
plain_value => sub {
my ($visitor, $value) = @_;
if ($value !~ /$re/) {
return $value;
}my $method = $1;
$method =~ s/\./_/g;
return $self->$method;
}
);
return $v->visit($config);
}