NAME
ModPerl::PackageRegistry - Map URIs to perl package namespaces
SYNOPSIS
Apache:
<Location /dynamic>
SetHandler perl-script
PerlResponseHandler ModPerl::PackageRegistry
PackageNamespace MyWebsite::pages
PackageBase /dynamic
PackageIndex index
PackageHandler ->page
</Location>
Perl:
package MyWebsite::pages::index;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Const q(OK);
return 1;
sub page {
my($class, $r) = @_;
$r->do_stuff();
return OK;
}
DESCRIPTION
This mod_perl2 handler allows you to directly map a path in your apache 2.x server to a package namespace in perl. When the handler is invoked, it transforms the URI requested into the name of a perl module, and if that module is found, executes the handler specified by the PackageHandler
directive.
FINDING YOUR HANDLER
The transformation is done as follows:
The
PackageBase
directive is applied.If a URI is specified in the
PackageBase
directive, that is stripped from the beginning of the URI in the request. (eg; if the browser requests/foo/bar/baz
, andPackageBase
is/foo/bar
, we are going to be searching for/baz
.)PackageBase
defaults to "/".Note that
ModPerl::PackageRegistry
will decline to act as a handler ifPackageBase
is defined, and the URL the browser requested doesn't match it.Any file extensions are removed.
The dot (.) is not a good character for a perl module's name, so anything found after it is removed. This allows you to do stuff like:
<Files "*.pr"> SetHandler perl-script PerlResponseHandler ModPerl::PackageRegistry PackageNamespace MyPackage::foo </Files>
Then, if somebody requested
/some/stuff.pr
,ModPerl::PackageRegistry
would look for a handler inMyPackage::foo::some::stuff
.Slashes are converted to double-colons (::)
This is pretty self-explanitory; the web's namespace separator is
/
, whereas perl's is::
.PackageNamespace
is prepended to the package's name.Again, pretty self-explanitory; if
PackageNamespace
isfoo
and we're looking forbar::baz
, the actual package we're going to try to load isfoo::bar::baz
.PackageIndex
is applied if the request is for a directory.The
PackageIndex
parameter allows you to specify what to append to the package name if a directory was requested. For example, if somebody requested/somewhere/else
andPackageIndex
was set tohello
, we would be looking forMyPackage::foo::somehwere::else::hello
.
We then attempt to load the module. If loading the module is successful, then we try to invoke it's handler. The handler is specified by the PackageHandler
directive. (By default, it is set to the mod_perl default, handler
). If you would like your handler to be invoked as a method rather than a function, then place a "->" in front of the method's name, like so:
PackageHandler ->method
At that point, ModPerl::PackageRegistry
is done it's work and the rest is up to you!
NOTES
The Directory Must Exist
Apache needs to be able to at least find a directory to serve from, even if the content it's serving is from a perl namespace. One way around this is to make your DocumentRoot the start of your perl namespace, eg:
DocumentRoot /usr/local/lib/perl/5.8.4/MyWebsite/pages
PackageIndex
PackageIndex will only work correctly if ModPerl::PackageRegistry is the handler for your entire directory tree. This is because of the way Apache interprets the DirectoryIndex
directive.
If you have a handler for ".pl" files, that handler will be invoked when you request /foo.pl, whether or not foo.pl actually exists.
However, if you request /, and that is resolved to /index.pl by a DirectoryIndex
directive, index.pl must exist or else apache2 will return a NOT_FOUND
response without ever invoking your handler.
If you wish to mix static and dynamic content in the same directory tree, there are three ways (that I know of) to get around this problem.
Make stub files for all of your indexes
If you have an empty file called
index.whatever
in each of your directories, that will cause your handler to be invoked as usual.Make your DocumentRoot your perl namespace's root.
Also solves the "Directory Must Exist" problem above, but this means that you have to scatter your static content around with your perl modules. (Is that actually such a bad thing?)
Use a LocationMatch directive to force apache to use your handler for directories
Like so:
<LocationMatch "/$"> SetHandler perl-script PerlResponseHandler ModPerl::PackageRegistry PackageIndex index PackageNamespace MyWebsite::pages </LocationMatch>
AUTHOR
Tyler "Crackerjack" MacDonald <japh@crackerjack.net>.
The "TestCommon::LogDiff" package, used by the test suite, was pilfered from the mod_perl 2.0.2 distribution.
LICENSE
This is free software; you may redistribute it under the same terms as perl itself.