Apache2-Controller
view release on metacpan or search on metacpan
lib/Apache2/Controller.pm view on Meta::CPAN
You can use or subclass L<Apache2::Controller::X>,
to use C<< a2cx() >>,
or you can throw your own exception objects,
or just C<< die() >>, or C<< croak() >>,
or set C<< $self->status >>, headers etc., possibly printing content,
or return the appropriate status from your controller method.
See L<Apache2::Controller::X> for help on throwing exceptions
with HTTP status, data dumps, etc.
If your code does break, die or throw an exception, this is
caught by Apache2::Controller. If your controller module implements
an C<<error() >> method,
then C<< $handler->error() >> will be called passing the C<< $EVAL_ERROR >>
or exception object as the first argument.
package MyApp::C::Foo;
use YAML::Syck;
# ...
sub error {
my ($self, $X) = @_;
$self->status( Apache2::Const::HTTP_BAD_REQUEST );
$self->content_type('text/plain');
$self->print("Take this job and shove it!\n", "\n", $X, "\n");
if ($X->isa('Apache2::Controller::X')) {
# usually you wouldn't show gory details to the user...
$self->print(Dump($X->dump)) if $X->dump;
$self->print($X->trace) if $X->trace;
}
}
For instance
L<Apache2::Controller::Render::Template> implements
C<< error() >> for you, which looks for
the appropriately named error template as
F<template_dir/errors/###.html>.
Of course, all exceptions are sent to the error log using
L<Log::Log4perl> DEBUG() before the handler completes, and
any refusal status greater or equal to 400 (HTTP_BAD_REQUEST)
will be written to the access log with L<Apache2::Log> log_reason()
using the first few characters of the error.
See L<Apache2::Controller::Session/ERRORS> for how to control
whether or not a session is saved. Usually it is automatically
saved, but not if you have an error.
C<< error() >> does not have to roll back DBI handles if you
use L<Apache2::Controller::DBI::Connector>, as this is
rolled back automatically in the C<< PerlLogHandler >>
phase if you don't commit the transaction.
=head1 CONTROLLER CLOSURES
Apache2::Controller's package space structure lets you take advantage
of closures that access variables in your controller subclass
package space, which are cached by modperl in child processes
across independent web requests. Be careful with that and use
Devel::Size to keep memory usage down. I have no idea how this
would work under threaded mpm.
=head1 CONTENT TYPE
Your controller should set content type with C<< $self->content_type() >>
to something specific if you need that. Otherwise it will let
mod_perl set it to whatever it chooses when you start to print.
This is usually text/html.
=head1 LOGGING
Apache2::Controller uses L<Log::Log4perl>. See that module
for information on how to set up a format file or statement.
For example, in a perl startup script called at Apache2 start time,
do something like:
use Log::Log4perl;
log4perl.rootLogger=DEBUG, LogFile
log4perl.appender.LogFile=Log::Log4perl::Appender::File
log4perl.appender.LogFile.filename=/var/log/mysite_error_log
log4perl.appender.LogFile.layout=PatternLayout
log4perl.appender.LogFile.layout.ConversionPattern=%M [%L]: %m%n
};
Log::Log4perl->init(\$logconf);
These settings will be cloned to every modperl child on fork.
=head1 MVC
Apache2::Controller provides the controller, mainly.
L<Apache2::Controller::Render::Template> is one example
of a view that can be used as a second base with
C<use base> in your controller module. As for the Model
part of Model-View-Controller, Apache2::Controller leaves
that entirely up to you and does not force you to
wrap anything in an abstraction class.
The C<handler()> subroutine is in your base class and your
controller modules will be running from memory in the mod_perl
child interpreter. So,
you can use package namespace effectively to store data
that will persist in the mod_perl child across requests.
=head1 LOAD BALANCING
A2C does not have to load
all site modules for every page handler, which could help with load-balancing
highly optimized handlers for specific URI's while having a universal
application installer.
Picture if you will, a programming utopia in which all engineers
are respected, highly paid and content, and managers make
correct decisions to rely on open-source software.
You deploy the same Apache, the
same CPAN modules and your whole application package to every server,
and attach a url-generating subroutine to the L<Template|Template> stash
that puts in a different hostname when the URI is one of your
load-intensive functions.
<a href="[% myurl('/easy') %]">easy</a> "http://pony.x.y/easy"
( run in 0.458 second using v1.01-cache-2.11-cpan-140bd7fdf52 )