]> wagnertech.de Git - kivitendo-erp.git/blob - SL/Controller/Base.pm
Dokumentation
[kivitendo-erp.git] / SL / Controller / Base.pm
1 package SL::Controller::Base;
2
3 use parent qw(Rose::Object);
4
5 use List::Util qw(first);
6
7 sub parse_html_template {
8   my $self   = shift;
9   my $name   = shift;
10   my $locals = shift || {};
11
12   return $::form->parse_html_template($name, { %{ $locals }, SELF => $self });
13 }
14
15 sub url_for {
16   my $self = shift;
17
18   return $_[0] if (scalar(@_) == 1) && !ref($_[0]);
19
20   my %params      = ref($_[0]) eq 'HASH' ? %{ $_[0] } : @_;
21   my $controller  = delete($params{controller}) || $self->_controller_name;
22   my $action      = delete($params{action})     || 'dispatch';
23   $params{action} = "${controller}/${action}";
24   my $query       = join('&', map { $::form->escape($_) . '=' . $::form->escape($params{$_}) } keys %params);
25
26   return "controller.pl?${query}";
27 }
28
29 sub _run_action {
30   my $self   = shift;
31   my $action = "action_" . shift;
32
33   return $self->_dispatch(@_) if $action eq 'action_dispatch';
34
35   $::form->error("Invalid action ${action} for controller " . ref($self)) if !$self->can($action);
36   $self->$action(@_);
37 }
38
39 sub _controller_name {
40   return (split(/::/, ref($_[0])))[-1];
41 }
42
43 sub _dispatch {
44   my $self    = shift;
45
46   my @actions = grep { m/^action_/ } keys %{ ref($self) . "::" };
47   my $action  = first { $::form->{$_} } @actions;
48
49   $self->$action(@_);
50 }
51
52 1;
53
54 __END__
55
56 =head1 NAME
57
58 SL::Controller::Base - base class for all action controllers
59
60 =head1 SYNOPSIS
61
62 =head2 OVERVIEW
63
64 This is a base class for all action controllers. Action controllers
65 provide subs that are callable by special URLs.
66
67 For each request made to the web server an instance of the controller
68 will be created. After the request has been served that instance will
69 handed over to garbage collection.
70
71 This base class is derived from L<Rose::Object>.
72
73 =head2 CONVENTIONS
74
75 The URLs have the following properties:
76
77 =over 2
78
79 =item *
80
81 The script part of the URL must be C<controller.pl>.
82
83 =item *
84
85 There must be a GET or POST parameter named C<action> containing the
86 name of the controller and the sub to call separated by C</>,
87 e.g. C<Message/list>.
88
89 =item *
90
91 The controller name is the package's name without the
92 C<SL::Controller::> prefix. At the moment only packages in the
93 C<SL::Controller> namespace are valid; sub-namespaces are not
94 allowed. The package name must start with an upper-case letter.
95
96 =item *
97
98 The sub part of the C<action> parameter is the name of the sub to
99 call. However, the sub's name is automatically prefixed with
100 C<action_>. Therefore for the example C<Message/list> the sub
101 C<SL::DB::Message::action_list> would be called. This in turn means
102 that subs whose name does not start with C<action_> cannot be invoked
103 directly via the URL.
104
105 =back
106
107 =head2 INDIRECT DISPATCHING
108
109 In the case that there are several submit buttons on a page it is
110 often impractical to have a single C<action> parameter match up
111 properly. For such a case a special dispatcher method is available. In
112 that case the C<action> parameter of the URL must be
113 C<Controller/dispatch>.
114
115 The C<SL::Controller::Base::_dispatch> method will iterate over all
116 subs in the controller package whose names start with C<action_>. The
117 first one for which there's a GET or POST parameter with the same name
118 and that's trueish is called.
119
120 Usage from a template usually looks like this:
121
122   <form method="POST" action="controller.pl">
123     ...
124     <input type="hidden" name="action" value="Message/dispatch">
125     <input type="submit" name="action_mark_as_read" value="Mark messages as read">
126     <input type="submit" name="action_delete" value="Delete messages">
127   </form>
128
129 The dispatching is handled by the function L</_dispatch>.
130
131 =head1 FUNCTIONS
132
133 =head2 PUBLIC HELPER FUNCTIONS
134
135 These functions are supposed to be called by sub-classed controllers.
136
137 =over 4
138
139 =item C<parse_html_template $file_name, $local_variables>
140
141 Outputs an HTML template. It is a thin wrapper around
142 C<Form::parse_html_template> which also adds the current object as the
143 template variable C<SELF>.
144
145 =item C<url_for $url>
146
147 =item C<url_for $params>
148
149 =item C<url_for %params>
150
151 Creates an URL for the given parameters suitable for calling an action
152 controller. If there's only one scalar parameter then it is returned
153 verbatim.
154
155 Otherwise the parameters are given either as a single hash ref
156 parameter or as a normal hash.
157
158 The controller to call is given by C<$params{controller}>. It defaults
159 to the current controller as returned by
160 L</_controller_name>.
161
162 The action to call is given by C<$params{action}>. It defaults to
163 C<dispatch>.
164
165 All other key/value pairs in C<%params> are appended as GET parameters
166 to the URL.
167
168 Usage from a template might look like this:
169
170   <a href="[% SELF.url_for(controller => 'Message', action => 'new', recipient_id => 42) %]">create new message</a>
171
172 =back
173
174 =head2 PRIVATE FUNCTIONS
175
176 These functions are supposed to be used from this base class only.
177
178 =over 4
179
180 =item C<_controller_name>
181
182 Returns the name of the curernt controller package without the
183 C<SL::Controller::> prefix.
184
185 =item C<_dispatch>
186
187 Implements the method lookup for indirect dispatching mentioned in the
188 section L</INDIRECT DISPATCHING>.
189
190 =item C<_run_action $action>
191
192 Executes a sub based on the value of C<$action>. C<$action> is the sub
193 name part of the C<action> GET or POST parameter as described in
194 L</CONVENTIONS>.
195
196 If C<$action> equals C<dispatch> then the sub L</_dispatch> in this
197 base class is called for L</INDIRECT DISPATCHING>. Otherwise
198 C<$action> is prefixed with C<action_>, and that sub is called on the
199 current controller instance.
200
201 =back
202
203 =head1 AUTHOR
204
205 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
206
207 =cut