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