1 package Reaction::UI::Controller::Collection::CRUD;
5 use base 'Reaction::UI::Controller::Collection';
8 use aliased 'Reaction::UI::ViewPort::Action';
10 sub _build_action_viewport_map {
11 my $map = shift->next::method(@_);
12 map{ $map->{$_} = Action } qw/create update delete delete_all/;
16 sub _build_action_viewport_args {
17 my $args = shift->next::method(@_);
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 ] } },
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 ] ] } },
39 sub get_model_action {
40 my ($self, $c, $name, $target) = @_;
42 if ($target->can('action_for')) {
43 return $target->action_for($name, ctx => $c);
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);
53 sub create :Chained('base') :PathPart('create') :Args(0) {
56 next_action => 'list',
57 on_apply_callback => sub { $self->after_create_callback($c => @_); },
59 $self->basic_model_action( $c, $vp_args);
62 sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) {
64 $self->basic_model_action( $c, { next_action => 'list'});
67 sub after_create_callback {
68 my ($self, $c, $vp, $result) = @_;
69 return $self->redirect_to
70 ( $c, 'update', [ @{$c->req->captures}, $result->id ] );
73 sub update :Chained('object') :Args(0) {
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);
82 sub delete :Chained('object') :Args(0) {
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);
91 sub basic_model_action {
92 my ($self, $c, $vp_args) = @_;
94 my $target = exists $c->stash->{object} ?
95 $c->stash->{object} : $self->get_collection($c);
97 my $action_name = join('', map{ ucfirst } split('_', $c->stack->[-1]->name));
98 my $model = $self->get_model_action($c, $action_name, $target);
99 return $self->basic_page($c, { model => $model, %{$vp_args||{}} });
108 Reaction::UI::Controller::CRUD - Basic CRUD functionality for Reaction::InterfaceModel data
112 Controller class which extends L<Reaction::UI::Controller::Collection> to
113 provide basic Create / Update / Delete / DeleteAll actions.
115 Building on the base of the Collection controller this controller allows you to
116 easily create complex and highly flexible CRUD functionality for your
117 InterfaceModel models by providing a simple way to render and process your
118 custom InterfaceModel Actions and customize built-ins.
122 =head2 get_model_action $c, $action_name, $target_im
124 Get an instance of the C<$action_name>
125 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> for model C<$target>
126 This action is suitable for passing to an
127 C<Action|Reaction::UI::ViewPort::Action> viewport
129 =head2 after_create_callback $c, $vp, $result
131 When a <create> action is applied, move the user to the new object's,
134 =head2 basic_model_action $c, \%vp_args
136 Extension to C<basic_page> which automatically instantiates an
137 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> with the right
138 data target using C<get_model_action>
140 =head2 _build_action_viewport_map
142 Map C<create>, C<update>, C<delete> and C<delete_all> to use the
143 C<Action|Reaction::UI::ViewPort::Action> viewport by default.
145 =head2 _build_action_viewport_args
147 Add action_prototypes to the C<list> action so that action links render correctly in L<ListView|Rection::UI::ViewPort::Listview>.
153 Chaned to C<base>. Create a new member of the collection represented by
154 this controller. By default it attaches the C<after_create_callback> to
155 DWIM after apply operations.
157 See L<Create|Reaction::InterfaceModel::Action::DBIC::ResultSet::Create>
162 Chained to B<base>, delete all the members of the B<collection>. In most cases
163 this is very much like a C<TRUNCATE> operation.
165 See L<DeleteAll|Reaction::InterfaceModel::Action::DBIC::ResultSet::DeleteAll>
170 Chained to C<object>, update a single object.
172 See L<Update|Reaction::InterfaceModel::Action::DBIC::Result::Update>
177 Chained to C<object>, deletee a single object.
180 See L<Delete|Reaction::InterfaceModel::Action::DBIC::Result::Delete>
185 L<Reaction::UI::Controller::Collection>, L<Reaction::UI::Controller>
189 See L<Reaction::Class> for authors.
193 See L<Reaction::Class> for the license.