Commit | Line | Data |
89b70ba7 |
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 | |
c8fbb8ad |
8 | use aliased 'Reaction::UI::ViewPort::Action'; |
8cc0103d |
9 | use aliased 'Reaction::UI::ViewPort::ListView'; |
89b70ba7 |
10 | |
11 | sub _build_action_viewport_map { |
37728bba |
12 | my $self = shift; |
13 | my $map = $self->next::method(@_); |
14 | $map->{list} = ListView if exists $map->{list}; |
15 | |
b3cb974a |
16 | #my %allowed = map { $_ => undef } |
17 | # ( @{$self->default_member_actions}, @{$self->default_collection_actions} ); |
336b3bb0 |
18 | my @local_actions = qw/create update delete delete_all/; |
b3cb974a |
19 | #$map->{$_} = Action for grep { exists $allowed{$_} } @local_actions; |
37728bba |
20 | |
b3cb974a |
21 | $map->{$_} = Action for @local_actions; |
89b70ba7 |
22 | return $map; |
23 | } |
24 | |
37728bba |
25 | sub _build_default_member_actions { |
26 | [ @{shift->next::method(@_)}, qw/update delete/ ]; |
27 | } |
28 | |
29 | sub _build_default_collection_actions { |
30 | [ @{shift->next::method(@_)}, qw/create delete_all/ ]; |
89b70ba7 |
31 | } |
32 | |
33 | sub get_model_action { |
34 | my ($self, $c, $name, $target) = @_; |
37728bba |
35 | return $target->action_for($name, ctx => $c); |
89b70ba7 |
36 | } |
89b70ba7 |
37 | sub create :Chained('base') :PathPart('create') :Args(0) { |
38 | my ($self, $c) = @_; |
747a1feb |
39 | my $apply = sub { $self->after_create_callback( @_) }; |
40 | my $close = sub { $self->on_create_close_callback( @_) }; |
89b70ba7 |
41 | my $vp_args = { |
893bf4f1 |
42 | target => ($c->stash->{collection} || $self->get_collection($c)), |
747a1feb |
43 | on_apply_callback => $self->make_context_closure($apply), |
44 | on_close_callback => $self->make_context_closure($close), |
52f292b2 |
45 | }; |
5d86015d |
46 | $self->basic_model_action( $c, $vp_args); |
89b70ba7 |
47 | } |
48 | |
49 | sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) { |
50 | my ($self, $c) = @_; |
747a1feb |
51 | my $close = sub { $self->on_delete_all_close_callback( @_) }; |
37728bba |
52 | $self->basic_model_action( $c, { |
893bf4f1 |
53 | target => ($c->stash->{collection} || $self->get_collection($c)), |
747a1feb |
54 | on_close_callback => $self->make_context_closure($close), |
52f292b2 |
55 | }); |
56 | } |
57 | |
58 | sub on_delete_all_close_callback { |
747a1feb |
59 | my($self, $c) = @_; |
60 | $self->redirect_to($c, 'list'); |
89b70ba7 |
61 | } |
62 | |
63 | sub after_create_callback { |
747a1feb |
64 | my ($self, $c, $vp, $result) = @_; |
89b70ba7 |
65 | return $self->redirect_to |
66 | ( $c, 'update', [ @{$c->req->captures}, $result->id ] ); |
67 | } |
68 | |
52f292b2 |
69 | sub on_create_close_callback { |
70 | my($self, $c, $vp) = @_; |
747a1feb |
71 | $self->redirect_to( $c, 'list' ); |
52f292b2 |
72 | } |
73 | |
89b70ba7 |
74 | sub update :Chained('object') :Args(0) { |
75 | my ($self, $c) = @_; |
747a1feb |
76 | my $close = sub { $self->on_update_close_callback( @_) }; |
52f292b2 |
77 | my $vp_args = { |
747a1feb |
78 | on_close_callback => $self->make_context_closure($close), |
52f292b2 |
79 | }; |
80 | $self->basic_model_action( $c, $vp_args); |
81 | } |
82 | |
83 | sub on_update_close_callback { |
747a1feb |
84 | my($self, $c) = @_; |
89b70ba7 |
85 | #this needs a better solution. currently thinking about it |
747a1feb |
86 | my @cap = @{$c->req->captures}; |
89b70ba7 |
87 | pop(@cap); # object id |
52f292b2 |
88 | $self->redirect_to($c, 'list', \@cap); |
89b70ba7 |
89 | } |
90 | |
91 | sub delete :Chained('object') :Args(0) { |
92 | my ($self, $c) = @_; |
747a1feb |
93 | my $close = sub { $self->on_update_close_callback( @_) }; |
52f292b2 |
94 | my $vp_args = { |
747a1feb |
95 | on_close_callback => $self->make_context_closure($close), |
52f292b2 |
96 | }; |
b68d6a35 |
97 | $self->basic_model_action( $c, $vp_args); |
89b70ba7 |
98 | } |
99 | |
aee256be |
100 | sub basic_model_action { |
89b70ba7 |
101 | my ($self, $c, $vp_args) = @_; |
893bf4f1 |
102 | my $stash = $c->stash; |
103 | my $target = delete $vp_args->{target}; |
104 | $target ||= ($stash->{object} || $stash->{collection} || $self->get_collection($c)); |
89b70ba7 |
105 | |
7d3fe0d2 |
106 | my $action_name = join('', map{ ucfirst } split('_', $c->stack->[-1]->name)); |
107 | my $model = $self->get_model_action($c, $action_name, $target); |
5d86015d |
108 | return $self->basic_page($c, { model => $model, %{$vp_args||{}} }); |
89b70ba7 |
109 | } |
110 | |
111 | 1; |
7d3fe0d2 |
112 | |
113 | __END__ |
114 | |
115 | =head1 NAME |
116 | |
117 | Reaction::UI::Controller::CRUD - Basic CRUD functionality for Reaction::InterfaceModel data |
118 | |
119 | =head1 DESCRIPTION |
120 | |
121 | Controller class which extends L<Reaction::UI::Controller::Collection> to |
122 | provide basic Create / Update / Delete / DeleteAll actions. |
123 | |
124 | Building on the base of the Collection controller this controller allows you to |
125 | easily create complex and highly flexible CRUD functionality for your |
126 | InterfaceModel models by providing a simple way to render and process your |
127 | custom InterfaceModel Actions and customize built-ins. |
128 | |
129 | =head1 METHODS |
130 | |
131 | =head2 get_model_action $c, $action_name, $target_im |
132 | |
133 | Get an instance of the C<$action_name> |
134 | L<InterfaceModel::Action|Reaction::InterfaceModel::Action> for model C<$target> |
135 | This action is suitable for passing to an |
136 | C<Action|Reaction::UI::ViewPort::Action> viewport |
137 | |
138 | =head2 after_create_callback $c, $vp, $result |
139 | |
140 | When a <create> action is applied, move the user to the new object's, |
141 | C<update> page. |
142 | |
143 | =head2 basic_model_action $c, \%vp_args |
144 | |
145 | Extension to C<basic_page> which automatically instantiates an |
146 | L<InterfaceModel::Action|Reaction::InterfaceModel::Action> with the right |
147 | data target using C<get_model_action> |
148 | |
149 | =head2 _build_action_viewport_map |
150 | |
b3cb974a |
151 | Map C<create>, C<update>, C<delete> and C<delete_all> to use the |
152 | L<Action|Reaction::UI::ViewPort::Action> viewport by default and have C<list> |
153 | use L<ListView|Reaction::UI::ViewPort::ListView> by default. |
154 | |
155 | =head2 _build_default_member_actions |
7d3fe0d2 |
156 | |
b3cb974a |
157 | Add C<update> and C<delete> to the list of default actions. |
7d3fe0d2 |
158 | |
b3cb974a |
159 | =head2 _build_default_collection_actions |
160 | |
161 | Add C<create> and C<delete_all> to the list of default actions. |
7d3fe0d2 |
162 | |
163 | =head1 ACTIONS |
164 | |
165 | =head2 create |
166 | |
167 | Chaned to C<base>. Create a new member of the collection represented by |
168 | this controller. By default it attaches the C<after_create_callback> to |
169 | DWIM after apply operations. |
170 | |
171 | See L<Create|Reaction::InterfaceModel::Action::DBIC::ResultSet::Create> |
172 | for more info. |
173 | |
174 | =head2 delete_all |
175 | |
176 | Chained to B<base>, delete all the members of the B<collection>. In most cases |
177 | this is very much like a C<TRUNCATE> operation. |
178 | |
179 | See L<DeleteAll|Reaction::InterfaceModel::Action::DBIC::ResultSet::DeleteAll> |
180 | for more info. |
181 | |
182 | =head2 update |
183 | |
184 | Chained to C<object>, update a single object. |
185 | |
186 | See L<Update|Reaction::InterfaceModel::Action::DBIC::Result::Update> |
187 | for more info. |
188 | |
189 | =head2 delete |
190 | |
b3cb974a |
191 | Chained to C<object>, delete a single object. |
7d3fe0d2 |
192 | |
193 | See L<Delete|Reaction::InterfaceModel::Action::DBIC::Result::Delete> |
194 | for more info. |
195 | |
196 | =head1 SEE ALSO |
197 | |
198 | L<Reaction::UI::Controller::Collection>, L<Reaction::UI::Controller> |
199 | |
200 | =head1 AUTHORS |
201 | |
202 | See L<Reaction::Class> for authors. |
203 | |
204 | =head1 LICENSE |
205 | |
206 | See L<Reaction::Class> for the license. |
207 | |
208 | =cut |