the forwards on basic_page and basic_model_action were breaking config merging at...
[catagits/Reaction.git] / lib / Reaction / UI / Controller / Collection / CRUD.pm
1 package Reaction::UI::Controller::Collection::CRUD;
2
3 use strict;
4 use warnings;
5 use base 'Reaction::UI::Controller::Collection';
6 use Reaction::Class;
7
8 use aliased 'Reaction::UI::ViewPort::Action';
9
10 sub _build_action_viewport_map {
11   my $map = shift->next::method(@_);
12   map{ $map->{$_} = Action } qw/create update delete delete_all/;
13   return $map;
14 }
15
16 sub _build_action_viewport_args {
17   my $args = shift->next::method(@_);
18   $args->{list} =
19     { action_prototypes =>
20       [ { label => 'Create', action => sub {
21             [ '', 'create',    $_[1]->req->captures ] } },
22         { label => 'Delete all', action => sub {
23             [ '', 'delete_all', $_[1]->req->captures ] } },
24       ],
25       Member =>
26       { action_prototypes =>
27         [ { label => 'View', action => sub {
28               [ '', 'view', [ @{$_[1]->req->captures},   $_[0]->__id ] ] } },
29           { label => 'Edit', action => sub {
30               [ '', 'update', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } },
31           { label => 'Delete', action => sub {
32               [ '', 'delete', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } },
33         ],
34       },
35     };
36   return $args;
37 }
38
39 sub get_model_action {
40   my ($self, $c, $name, $target) = @_;
41
42   if ($target->can('action_for')) {
43     return $target->action_for($name, ctx => $c);
44   }
45
46   #can we please kill this already?
47   my $model_name = "Action::${name}".$self->model_name;
48   my $model = $c->model($model_name);
49   confess "no such Model $model_name" unless $model;
50   return $model->new(target_model => $target, ctx => $c);
51 }
52
53 sub create :Chained('base') :PathPart('create') :Args(0) {
54   my ($self, $c) = @_;
55   my $vp_args = {
56                  next_action => 'list',
57                  on_apply_callback => sub { $self->after_create_callback($c => @_); },
58                 };
59   $self->basic_model_action( $c, [$vp_args]);
60 }
61
62 sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) {
63   my ($self, $c) = @_;
64   $self->basic_model_action( $c,  [{ next_action => 'list'}]);
65 }
66
67 sub after_create_callback {
68   my ($self, $c, $vp, $result) = @_;
69   return $self->redirect_to
70     ( $c, 'update', [ @{$c->req->captures}, $result->id ] );
71 }
72
73 sub update :Chained('object') :Args(0) {
74   my ($self, $c) = @_;
75   #this needs a better solution. currently thinking about it
76   my @cap = @{$c->req->captures};
77   pop(@cap); # object id
78   my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]};
79   $self->basic_model_action( $c, [$vp_args]);
80 }
81
82 sub delete :Chained('object') :Args(0) {
83   my ($self, $c) = @_;
84   #this needs a better solution. currently thinking about it
85   my @cap = @{$c->req->captures};
86   pop(@cap); # object id
87   my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]};
88   $self->basic_model_action( $c, [$vp_args]);
89 }
90
91 sub basic_model_action {
92   my ($self, $c, $vp_args) = @_;
93
94   my $target = exists $c->stash->{object} ?
95     $c->stash->{object} : $self->get_collection($c);
96
97   my $cat_action_name = $c->stack->[-1]->name;
98   my $im_action_name  = join('', (map{ ucfirst } split('_', $cat_action_name)));
99   return $self->push_viewport
100     (
101      $self->action_viewport_map->{$cat_action_name},
102      model => $self->get_model_action($c, $im_action_name, $target),
103      %{ $vp_args || {} },
104      %{ $self->action_viewport_args->{$cat_action_name} || {} },
105     );
106 }
107
108 1;