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