use namespace::clean -excpept => 'meta';
sub _setup_dynamic_component {
- my ($app, $name, $config) = @_;
+ my ($app, $name, $config, $component_method) = @_;
my $appclass = blessed($app) || $app;
my $type = $name;
my $meta = Moose->init_meta( for_class => $name );
$meta->superclasses('Catalyst::' . $type);
- $meta->add_method(
-
- COMPONENT
- => sub {
- my ($component_class_name, $app, $args) = @_;
-
- my $class = delete $args->{class};
- Class::MOP::load_class($class);
-
- $class->new($args);
- });
+ $meta->add_method( COMPONENT => $component_method );
$meta->make_immutable;
with 'CatalystX::DynamicComponent'
=> { alias => { _setup_dynamic_component => '_setup_dynamic_controller' } };
-requires 'setup_components';
+requires 'setup_actionts';
-after 'setup_components' => sub { shift->_setup_dynamic_controllers(@_); };
+before 'setup_actions' => sub { shift->_setup_dynamic_controllers(@_); };
sub _setup_dynamic_controllers {
my ($app) = @_;
sub _reflect_model_to_controller {
my ( $app, $model_name, $model ) = @_;
+ my $class = blessed($app) || $app;
+
my $controller_name = $model_name;
$controller_name =~ s/::Model::/::Controller::/;
- $app->_setup_dynamic_controller( $controller_name );
+ my $suffix = $model_name;
+ $suffix =~ s/^.*::Model:://;
+
+ my $controller = $app->_setup_dynamic_controller( $controller_name, {}, sub {
+ shift->next::method(@_); # Just use the default COMPONENT method
+ });
+ my $meta = $controller->meta;
+ $meta->make_mutable; # Dirty, I should build the class, add the methods, then
+ # last of all make it a component
+
+ my $methods = $model->meta->get_method_map;
+ foreach my $method_name (keys %$methods) {
+ $controller->meta->add_method(
+ # Note need to pass model name, as the method actually comes from
+ # the underlying model class, not the Catalyst shim class we autogenerated.
+ $method_name => $app->generate_reflected_controller_action_method($suffix, $methods->{$method_name})
+ );
+ }
+ $meta->make_immutable;
+}
+
+sub generate_reflected_controller_action_method {
+ my ( $app, $model, $method ) = @_;
+ my $method_name = $method->name; # Is it worth passing the actual method object here?
+ sub {
+ my ($self, $c, @args) = @_;
+ $c->res->header('X-From-Model', $model);
+ $c->res->header('X-From-Model-Data', $c->model($model)->$method_name(@args));
+ $c->res->body('OK');
+ };
}
1;
my $app_name = blessed($app) || $app;
my $model_prefix = 'Model::';
- my $model_hash = $app->config || {};
+ my $config = $app->config || {};
- foreach my $model_name ( grep { /^$model_prefix/ } keys %$model_hash ) {
+ foreach my $model_name ( grep { /^$model_prefix/ } keys %$config ) {
my $model_class_name = $app_name . '::' . $model_name;
- $app->_setup_dynamic_model( $model_class_name, $model_hash->{$model_name} );
+
+ $app->_setup_dynamic_model( $model_class_name, $config->{$model_name},
+ sub {
+ my ($component_class_name, $app, $args) = @_;
+
+ my $class = delete $args->{class};
+ Class::MOP::load_class($class);
+
+ $class->new($args);
+ });
}
}