d80fca16d71d99d729c27b26c58cea522545eb55
[kivitendo-erp.git] / SL / Controller / Base.pm
1 package SL::Controller::Base;
2
3 use strict;
4
5 use parent qw(Rose::Object);
6
7 use Carp;
8 use List::Util qw(first);
9
10 #
11 # public/helper functions
12 #
13
14 sub url_for {
15   my $self = shift;
16
17   return $_[0] if (scalar(@_) == 1) && !ref($_[0]);
18
19   my %params      = ref($_[0]) eq 'HASH' ? %{ $_[0] } : @_;
20   my $controller  = delete($params{controller}) || $self->_controller_name;
21   my $action      = delete($params{action})     || 'dispatch';
22   $params{action} = "${controller}/${action}";
23   my $query       = join('&', map { $::form->escape($_) . '=' . $::form->escape($params{$_}) } keys %params);
24
25   return "controller.pl?${query}";
26 }
27
28 sub redirect_to {
29   my $self = shift;
30   my $url  = $self->url_for(@_);
31
32   print $::cgi->redirect($url);
33 }
34
35 sub render {
36   my $self               = shift;
37   my $template           = shift;
38   my ($options, %locals) = (@_ && ref($_[0])) ? @_ : ({ }, @_);
39
40   $options->{type}       = lc($options->{type} || 'html');
41   $options->{no_layout}  = 1 if $options->{type} eq 'js';
42
43   my $source;
44   if ($options->{inline}) {
45     $source = \$template;
46
47   } else {
48     $source = "templates/webpages/${template}." . $options->{type};
49     croak "Template file ${source} not found" unless -f $source;
50   }
51
52   if (!$options->{partial} && !$options->{inline} && !$::form->{header}) {
53     if ($options->{no_layout}) {
54       $::form->{header} = 1;
55       my $content_type  = $options->{type} eq 'js' ? 'text/javascript' : 'text/html';
56
57       print $::form->create_http_response(content_type => $content_type,
58                                           charset      => $::lx_office_conf{system}->{dbcharset} || Common::DEFAULT_CHARSET());
59
60     } else {
61       $::form->{title} = $locals{title} if $locals{title};
62       $::form->header;
63     }
64   }
65
66   my %params = ( %locals,
67                  AUTH     => $::auth,
68                  FLASH    => $::form->{FLASH},
69                  FORM     => $::form,
70                  LOCALE   => $::locale,
71                  LXCONFIG => \%::lx_office_conf,
72                  LXDEBUG  => $::lxdebug,
73                  MYCONFIG => \%::myconfig,
74                  SELF     => $self,
75                );
76
77   my $output;
78   my $parser = $self->_template_obj;
79   $parser->process($source, \%params, \$output) || croak $parser->error;
80
81   print $output unless $options->{inline} || $options->{no_output};
82
83   return $output;
84 }
85
86 #
87 # Before/after run hooks
88 #
89
90 sub run_before {
91   _add_hook('before', @_);
92 }
93
94 sub run_after {
95   _add_hook('after', @_);
96 }
97
98 my %hooks;
99
100 sub _add_hook {
101   my ($when, $class, $sub, %params) = @_;
102
103   foreach my $key (qw(only except)) {
104     $params{$key} = { map { ( $_ => 1 ) } @{ $params{$key} } } if $params{$key};
105   }
106
107   my $idx = "${when}/${class}";
108   $hooks{$idx} ||= [ ];
109   push @{ $hooks{$idx} }, { %params, code => $sub };
110 }
111
112 sub _run_hooks {
113   my ($self, $when, $action) = @_;
114
115   my $idx = "${when}/" . ref($self);
116
117   foreach my $hook (@{ $hooks{$idx} || [] }) {
118     next if ($hook->{only  } && !$hook->{only  }->{$action})
119          || ($hook->{except} &&  $hook->{except}->{$action});
120
121     if (ref($hook->{code}) eq 'CODE') {
122       $hook->{code}->($self);
123     } else {
124       my $sub = $hook->{code};
125       $self->$sub;
126     }
127   }
128 }
129
130 #
131 # private functions -- for use in Base only
132 #
133
134 sub _run_action {
135   my $self   = shift;
136   my $action = shift;
137   my $sub    = "action_${action}";
138
139   return $self->_dispatch(@_) if $action eq 'dispatch';
140
141   $::form->error("Invalid action '${action}' for controller " . ref($self)) if !$self->can($sub);
142
143   $self->_run_hooks('before', $action);
144   $self->$sub(@_);
145   $self->_run_hooks('after', $action);
146 }
147
148 sub _controller_name {
149   return (split(/::/, ref($_[0])))[-1];
150 }
151
152 sub _dispatch {
153   my $self    = shift;
154
155   no strict 'refs';
156   my @actions = map { s/^action_//; $_ } grep { m/^action_/ } keys %{ ref($self) . "::" };
157   my $action  = first { $::form->{"action_${_}"} } @actions;
158   my $sub     = "action_${action}";
159
160   $self->_run_hooks('before', $action);
161   $self->$sub(@_);
162   $self->_run_hooks('after', $action);
163 }
164
165 sub _template_obj {
166   my ($self) = @_;
167
168   $self->{__basepriv_template_obj} ||=
169     Template->new({ INTERPOLATE  => 0,
170                     EVAL_PERL    => 0,
171                     ABSOLUTE     => 1,
172                     CACHE_SIZE   => 0,
173                     PLUGIN_BASE  => 'SL::Template::Plugin',
174                     INCLUDE_PATH => '.:templates/webpages',
175                     COMPILE_EXT  => '.tcc',
176                     COMPILE_DIR  => $::lx_office_conf{paths}->{userspath} . '/templates-cache',
177                   }) || croak;
178
179   return $self->{__basepriv_template_obj};
180 }
181
182 1;
183
184 __END__
185
186 =head1 NAME
187
188 SL::Controller::Base - base class for all action controllers
189
190 =head1 SYNOPSIS
191
192 =head2 OVERVIEW
193
194 This is a base class for all action controllers. Action controllers
195 provide subs that are callable by special URLs.
196
197 For each request made to the web server an instance of the controller
198 will be created. After the request has been served that instance will
199 handed over to garbage collection.
200
201 This base class is derived from L<Rose::Object>.
202
203 =head2 CONVENTIONS
204
205 The URLs have the following properties:
206
207 =over 2
208
209 =item *
210
211 The script part of the URL must be C<controller.pl>.
212
213 =item *
214
215 There must be a GET or POST parameter named C<action> containing the
216 name of the controller and the sub to call separated by C</>,
217 e.g. C<Message/list>.
218
219 =item *
220
221 The controller name is the package's name without the
222 C<SL::Controller::> prefix. At the moment only packages in the
223 C<SL::Controller> namespace are valid; sub-namespaces are not
224 allowed. The package name must start with an upper-case letter.
225
226 =item *
227
228 The sub part of the C<action> parameter is the name of the sub to
229 call. However, the sub's name is automatically prefixed with
230 C<action_>. Therefore for the example C<Message/list> the sub
231 C<SL::DB::Message::action_list> would be called. This in turn means
232 that subs whose name does not start with C<action_> cannot be invoked
233 directly via the URL.
234
235 =back
236
237 =head2 INDIRECT DISPATCHING
238
239 In the case that there are several submit buttons on a page it is
240 often impractical to have a single C<action> parameter match up
241 properly. For such a case a special dispatcher method is available. In
242 that case the C<action> parameter of the URL must be
243 C<Controller/dispatch>.
244
245 The C<SL::Controller::Base::_dispatch> method will iterate over all
246 subs in the controller package whose names start with C<action_>. The
247 first one for which there's a GET or POST parameter with the same name
248 and that's trueish is called.
249
250 Usage from a template usually looks like this:
251
252   <form method="POST" action="controller.pl">
253     ...
254     <input type="hidden" name="action" value="Message/dispatch">
255     <input type="submit" name="action_mark_as_read" value="Mark messages as read">
256     <input type="submit" name="action_delete" value="Delete messages">
257   </form>
258
259 The dispatching is handled by the function L</_dispatch>.
260
261 =head2 HOOKS
262
263 Hooks are functions that are called before or after the controller's
264 action is called. The controller package defines the hooks, and those
265 hooks themselves are run as instance methods.
266
267 Hooks are run in the order they're added.
268
269 The return value of the hooks is discarded.
270
271 Hooks can be defined to run for all actions, for only specific actions
272 or for all actions except a list of actions. Each entry is the action
273 name, not the sub's name. Therefore in order to run a hook before one
274 of the subs C<action_edit> or C<action_save> is called the following
275 code can be used:
276
277   __PACKAGE__->run_before('things_to_do_before_edit_and_save', only => [ 'edit', 'save' ]);
278
279 =head1 FUNCTIONS
280
281 =head2 PUBLIC HELPER FUNCTIONS
282
283 These functions are supposed to be called by sub-classed controllers.
284
285 =over 4
286
287 =item C<render $template, [ $options, ] %locals>
288
289 Renders the template C<$template>. Provides other variables than
290 C<Form::parse_html_template> does.
291
292 C<$options>, if present, must be a hash reference. All remaining
293 parameters are slurped into C<%locals>.
294
295 What is rendered and how C<$template> is interpreted is determined by
296 the options I<type>, I<inline>, I<partial> and I<no_layout>.
297
298 If C<< $options->{inline} >> is trueish then C<$template> is a string
299 containing the template code to interprete. Additionally the output
300 will not be sent to the browser. Instead it is only returned to the
301 caller.
302
303 If C<< $options->{inline} >> is falsish then C<$template> is
304 interpreted as the name of a template file. It is prefixed with
305 "templates/webpages/" and postfixed with a file extension based on
306 C<< $options->{type} >>. C<< $options->{type} >> can be either C<html>
307 or C<js> and defaults to C<html>. An exception will be thrown if that
308 file does not exist.
309
310 If C<< $options->{partial} >> or C<< $options->{inline} >> is trueish
311 then neither the HTTP response header nor the standard HTML header is
312 generated.
313
314 Otherwise at least the HTTP response header will be generated based on
315 the template type (C<< $options->{type} >>).
316
317 If the template type is C<html> then the standard HTML header will be
318 output via C<< $::form->header >> with C<< $::form->{title} >> set to
319 C<$locals{title}> (the latter only if C<$locals{title}> is
320 trueish). Setting C<< $options->{no_layout} >> to trueish will prevent
321 this.
322
323 The template itself has access to the following variables:
324
325 =over 2
326
327 =item * C<AUTH> -- C<$::auth>
328
329 =item * C<FORM> -- C<$::form>
330
331 =item * C<LOCALE> -- C<$::locale>
332
333 =item * C<LXCONFIG> -- all parameters from C<config/lx_office.conf>
334 with the same name they appear in the file (first level is the
335 section, second the actual variable, e.g. C<system.dbcharset>,
336 C<features.webdav> etc)
337
338 =item * C<LXDEBUG> -- C<$::lxdebug>
339
340 =item * C<MYCONFIG> -- C<%::myconfig>
341
342 =item * C<SELF> -- the controller instance
343
344 =item * All items from C<%locals>
345
346 =back
347
348 Unless C<< $options->{inline} >> is trueish the function will send the
349 output to the browser.
350
351 The function will always return the output.
352
353 Example: Render a HTML template with a certain title and a few locals
354
355   $self->render('todo/list',
356                 title      => 'List TODO items',
357                 TODO_ITEMS => SL::DB::Manager::Todo->get_all_sorted);
358
359 Example: Render a string and return its content for further processing
360 by the calling function. No header is generated due to C<inline>.
361
362   my $content = $self->render('[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]',
363                               { type => 'js', inline => 1 });
364
365 Example: Render a JavaScript template and send it to the
366 browser. Typical use for actions called via AJAX:
367
368   $self->render('todo/single_item', { type => 'js' },
369                 item => $employee->most_important_todo_item);
370
371 =item C<url_for $url>
372
373 =item C<url_for $params>
374
375 =item C<url_for %params>
376
377 Creates an URL for the given parameters suitable for calling an action
378 controller. If there's only one scalar parameter then it is returned
379 verbatim.
380
381 Otherwise the parameters are given either as a single hash ref
382 parameter or as a normal hash.
383
384 The controller to call is given by C<$params{controller}>. It defaults
385 to the current controller as returned by
386 L</_controller_name>.
387
388 The action to call is given by C<$params{action}>. It defaults to
389 C<dispatch>.
390
391 All other key/value pairs in C<%params> are appended as GET parameters
392 to the URL.
393
394 Usage from a template might look like this:
395
396   <a href="[% SELF.url_for(controller => 'Message', action => 'new', recipient_id => 42) %]">create new message</a>
397
398 =item C<redirect_to %url_params>
399
400 Redirects the browser to a new URL by outputting a HTTP redirect
401 header. The URL is generated by calling L</url_for> with
402 C<%url_params>.
403
404 =item C<run_before $sub, %params>
405
406 =item C<run_after $sub, %params>
407
408 Adds a hook to run before or after certain actions are run for the
409 current package. The code to run is C<$sub> which is either the name
410 of an instance method or a code reference. If it's the latter then the
411 first parameter will be C<$self>.
412
413 C<%params> can contain two possible values that restrict the code to
414 be run only for certain actions:
415
416 =over 2
417
418 =item C<< only => \@list >>
419
420 Only run the code for actions given in C<@list>. The entries are the
421 action names, not the names of the sub (so it's C<list> instead of
422 C<action_list>).
423
424 =item C<< except => \@list >>
425
426 Run the code for all actions but for those given in C<@list>. The
427 entries are the action names, not the names of the sub (so it's
428 C<list> instead of C<action_list>).
429
430 =back
431
432 If neither restriction is used then the code will be run for any
433 action.
434
435 The hook's return values are discarded.
436
437 =back
438
439 =head2 PRIVATE FUNCTIONS
440
441 These functions are supposed to be used from this base class only.
442
443 =over 4
444
445 =item C<_controller_name>
446
447 Returns the name of the curernt controller package without the
448 C<SL::Controller::> prefix.
449
450 =item C<_dispatch>
451
452 Implements the method lookup for indirect dispatching mentioned in the
453 section L</INDIRECT DISPATCHING>.
454
455 =item C<_run_action $action>
456
457 Executes a sub based on the value of C<$action>. C<$action> is the sub
458 name part of the C<action> GET or POST parameter as described in
459 L</CONVENTIONS>.
460
461 If C<$action> equals C<dispatch> then the sub L</_dispatch> in this
462 base class is called for L</INDIRECT DISPATCHING>. Otherwise
463 C<$action> is prefixed with C<action_>, and that sub is called on the
464 current controller instance.
465
466 =back
467
468 =head1 AUTHOR
469
470 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
471
472 =cut