1 package Reaction::UI::Controller::Collection::CRUD;
5 use base 'Reaction::UI::Controller::Collection';
8 use aliased 'Reaction::UI::ViewPort::Action';
9 use aliased 'Reaction::UI::ViewPort::ListView';
11 sub _build_action_viewport_map {
13 my $map = $self->next::method(@_);
14 $map->{list} = ListView if exists $map->{list};
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;
21 $map->{$_} = Action for @local_actions;
25 sub _build_default_member_actions {
26 [ @{shift->next::method(@_)}, qw/update delete/ ];
29 sub _build_default_collection_actions {
30 [ @{shift->next::method(@_)}, qw/create delete_all/ ];
33 sub get_model_action {
34 my ($self, $c, $name, $target) = @_;
35 return $target->action_for($name, ctx => $c);
37 sub create :Chained('base') :PathPart('create') :Args(0) {
39 my $apply = sub { $self->after_create_callback( @_) };
40 my $close = sub { $self->on_create_close_callback( @_) };
42 on_apply_callback => $self->make_context_closure($apply),
43 on_close_callback => $self->make_context_closure($close),
45 $self->basic_model_action( $c, $vp_args);
48 sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) {
50 my $close = sub { $self->on_delete_all_close_callback( @_) };
51 $self->basic_model_action( $c, {
52 on_close_callback => $self->make_context_closure($close),
56 sub on_delete_all_close_callback {
58 $self->redirect_to($c, 'list');
61 sub after_create_callback {
62 my ($self, $c, $vp, $result) = @_;
63 return $self->redirect_to
64 ( $c, 'update', [ @{$c->req->captures}, $result->id ] );
67 sub on_create_close_callback {
68 my($self, $c, $vp) = @_;
69 $self->redirect_to( $c, 'list' );
72 sub update :Chained('object') :Args(0) {
74 my $close = sub { $self->on_update_close_callback( @_) };
76 on_close_callback => $self->make_context_closure($close),
78 $self->basic_model_action( $c, $vp_args);
81 sub on_update_close_callback {
83 #this needs a better solution. currently thinking about it
84 my @cap = @{$c->req->captures};
85 pop(@cap); # object id
86 $self->redirect_to($c, 'list', \@cap);
89 sub delete :Chained('object') :Args(0) {
91 my $close = sub { $self->on_update_close_callback( @_) };
93 on_close_callback => $self->make_context_closure($close),
95 $self->basic_model_action( $c, $vp_args);
98 sub basic_model_action {
99 my ($self, $c, $vp_args) = @_;
101 my $target = exists $c->stash->{object} ?
102 $c->stash->{object} : $self->get_collection($c);
104 my $action_name = join('', map{ ucfirst } split('_', $c->stack->[-1]->name));
105 my $model = $self->get_model_action($c, $action_name, $target);
106 return $self->basic_page($c, { model => $model, %{$vp_args||{}} });
115 Reaction::UI::Controller::CRUD - Basic CRUD functionality for Reaction::InterfaceModel data
119 Controller class which extends L<Reaction::UI::Controller::Collection> to
120 provide basic Create / Update / Delete / DeleteAll actions.
122 Building on the base of the Collection controller this controller allows you to
123 easily create complex and highly flexible CRUD functionality for your
124 InterfaceModel models by providing a simple way to render and process your
125 custom InterfaceModel Actions and customize built-ins.
129 =head2 get_model_action $c, $action_name, $target_im
131 Get an instance of the C<$action_name>
132 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> for model C<$target>
133 This action is suitable for passing to an
134 C<Action|Reaction::UI::ViewPort::Action> viewport
136 =head2 after_create_callback $c, $vp, $result
138 When a <create> action is applied, move the user to the new object's,
141 =head2 basic_model_action $c, \%vp_args
143 Extension to C<basic_page> which automatically instantiates an
144 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> with the right
145 data target using C<get_model_action>
147 =head2 _build_action_viewport_map
149 Map C<create>, C<update>, C<delete> and C<delete_all> to use the
150 L<Action|Reaction::UI::ViewPort::Action> viewport by default and have C<list>
151 use L<ListView|Reaction::UI::ViewPort::ListView> by default.
153 =head2 _build_default_member_actions
155 Add C<update> and C<delete> to the list of default actions.
157 =head2 _build_default_collection_actions
159 Add C<create> and C<delete_all> to the list of default actions.
165 Chaned to C<base>. Create a new member of the collection represented by
166 this controller. By default it attaches the C<after_create_callback> to
167 DWIM after apply operations.
169 See L<Create|Reaction::InterfaceModel::Action::DBIC::ResultSet::Create>
174 Chained to B<base>, delete all the members of the B<collection>. In most cases
175 this is very much like a C<TRUNCATE> operation.
177 See L<DeleteAll|Reaction::InterfaceModel::Action::DBIC::ResultSet::DeleteAll>
182 Chained to C<object>, update a single object.
184 See L<Update|Reaction::InterfaceModel::Action::DBIC::Result::Update>
189 Chained to C<object>, delete a single object.
191 See L<Delete|Reaction::InterfaceModel::Action::DBIC::Result::Delete>
196 L<Reaction::UI::Controller::Collection>, L<Reaction::UI::Controller>
200 See L<Reaction::Class> for authors.
204 See L<Reaction::Class> for the license.