NAME
CGI::Application::Plugin::Config::General - Add Config::General Support to CGI::Application
VERSION
Version 0.03
SYNOPSIS
Simple Access to Configuration
In your CGI::Application-based module:
use base 'CGI::Application';
use CGI::Application::Plugin::Config::General;
sub cgiapp_init {
my $self = shift;
# Set config file and other options
$self->conf->init(
-ConfigFile => 'app.conf',
);
}
sub my_run_mode {
my $self = shift;
# get entire configuration
my %conf = $self->conf->getall;
# get entire configuration (as a reference)
my $conf = $self->conf->getall;
# get single config parameter
my $value = $self->conf->param('some_value');
# get underlying Config::General object
my $obj = $self->conf->obj;
}
Configuration Based on URL or Module
You can match a configuration section to the request URL, or to the module name. For instance, given the following configuration file:
admin_area = 0
<AppMatch ^MyApp::Admin>
admin_area = 1
title = Admin Area
</AppMatch>
<Location /cgi-bin/feedback.cgi>
title = Feedback Form
</Location>
The configuration will depend on how the script is called:
# URL: /cgi-bin/feedback.cgi?rm=add
# Module: MyApp::Feedback
print $self->conf->param('admin_area'); # 0
print $self->conf->param('title'); # 'Feedback Form'
# URL: /cgi-bin/admin/users.cgi
# Module: MyApp::Admin::Users
print $self->conf->param('admin_area'); # 1
print $self->conf->param('title'); # 'Admin Area'
Matching Configuration based on a Virtual Host
This module can also pick a configuration section based on the current virtual-host:
# httpd.conf
<VirtualHost _default_:8080>
SetEnv SITE_NAME REDSITE
</VirtualHost>
# in app.conf
<Site BLUESITE>
background = blue
foreground = white
</Site>
<Site REDSITE>
background = red
foreground = pink
</Site>
<Site GREENSITE>
background = darkgreen
foreground = lightgreen
</Site>
DESCRIPTION
This module allows you to easily access configuration data stored in Config::General
(i.e. Apache-style) config files.
You can also automatically match configuration sections to the request URL, or to the module name. This is similar to how Apache dynamically selects a configuration by matching the request URL to e.g. <Location>
and <LocationMatch>
sections.
You can also select configuration sections based on Virtual Host or by a variable you set in an .htaccess
file. This allows you to share a single application between many virtual hosts, each with its own unique configuration. This could be useful, for instance, in providing multiple themes for a single application.
Simple access to Configuration
This module provides a conf
method to your CGI::Application
object. First, you initialize the configuration system (typically in your cgiapp_init
method):
$self->conf->init(
-ConfigFile => 'app.conf',
);
The configuration file is parsed at this point and is available from this point on.
Then, within your run-modes you can retrieve configuration data:
# get entire configuration
my %conf = $self->conf->getall;
my $value = $conf{'some_value'};
# get entire configuration (as a reference)
my $conf = $self->conf->getall;
my $value = $conf{'some_value'};
# get single config parameter
my $value = $self->conf->param('some_value');
Multiple named Configurations
You can use more than one configuration by providing a name to the conf
method:
$self->conf('database')->init(
-ConfigFile => 'app.conf',
);
$self->conf('application')->init(
-ConfigFile => 'app.conf',
);
...
my %db_config = $self->conf('database')->getall;
my %app_config = $self->conf('application')->getall;
Configuration based on URL or Module
Within your configuration file, you can provide different configurations depending on the current URL, or on the package name of your application.
- <Site>
-
Matches against the
SITE_NAME
environment variable, using an exact match.# httpd.conf <VirtualHost _default_:8080> SetEnv SITE_NAME REDSITE </VirtualHost> # in app.conf <Site BLUESITE> background = blue foreground = white </Site> <Site REDSITE> background = red foreground = pink </Site> <Site GREENSITE> background = darkgreen foreground = lightgreen </Site>
You can use name your sections something other than
<Site>
, and you can use a different environment variable thanSITE_NAME
. SeeNotes on Site Matching
, below. - <SiteMatch>
-
Matches against the
SITE_NAME
environment variable using a regular expression.# httpd.conf <VirtualHost _default_:8080> SetEnv SITE_NAME REDSITE </VirtualHost> # in app.conf <Site BLUESITE> background = blue foreground = white </Site> <Site REDSITE> background = red foreground = pink </Site> <Site GREENSITE> background = darkgreen foreground = lightgreen </Site>
You can use name your sections something other than
<Site>
, and you can use a different environment variable thanSITE_NAME
. SeeNotes on Site Matching
, below. - <App>
-
Matches the Package name of your application module, for instance:
<App ABC_Books::Admin> ... </App>
The match is performed hierachically, like a filesystem path, except using
::
as a delimiter, instead of/
. The match is tied to the beginning of the package name, just like absolute paths. For instance, given the section:<App Admin> ... </App>
the packages
Admin
andAdmin::Users
would match, but the packagesFoo::Admin
andAdministrative
would not.For instance, given the section:
<App Admin> ... </App>
- <AppMatch>
-
Matches the package name of your application module, using a regular expression. The expression is not tied to the start of the string. For instance, given the section:
<AppMatch Admin> ... </AppMatch>
The following packages would all match:
Admin
,Admin::Users
,Foo::Admin
,Administrative
. - <Location>
-
Matches hierarchically against the request URI, including the path and the
PATH_INFO
components, but excluding the scheme, host, port and query string.So, for instance with the following URL:
http://bookstore.example.com/cgi-bin/category.cgi/fiction/?rm=list
The Location would be:
/cgi-bin/category.cgi/fiction/
This is obtained by calling the
url
method of the query object (eitherCGI
orCGI::Simple
):$path = $webapp->query->url('-absolute' => 1, '-path_info' => 1);
- <LocationMatch>
-
Matches against the request URI, using a regular expression.
Section Merge Order
The sections are matched in the following order:
Site: <Site> and <SiteMatch>
Package Name: <App> and <AppMatch>
URL: <Location> and <LocationMatch>
When there is more than one matching section at the same level of priority (e.g. two <Location>
sections, or both an <App>
and an <AppMatch>
section), then the sections are merged in the order of shortest match first.
Values in sections matched later override the values in sections matched earlier.
The idea is that the longer matches are more specific and should have priority.
Section Nesting
The sections can be nested inside each other. For instance:
<Site BOOKSHOP>
<Location /admin>
admin_books = 1
</Location>
</Site>
<Location /admin>
<Site RECORDSHOP>
admin_records = 1
</Site>
</Location>
<App Bookshop::>
<App Admin::>
</App>
</App>
By default, the sections can be nested up to two levels deep. You can change this by setting the -NestingDepth
parameter to init
.
Merging Configuration Values into your Template
You can easily pass values from your configuration files directly to your templates. This allows you to associate HTML titles with URLs, or keep text like copyright notices in your config file instead of your templates:
copyright_notice = Copyright (C) 1492 Christopher Columbus
<Location /about>
title = "Manifest Destiny, Inc. - About Us"
</Location>
<Location /contact>
title = "Manifest Destiny, Inc. - Contact Us"
</Location>
If you do this, you should consider keeping your database passwords and other sensitive data in a separate configuration file, in order to avoid accidentally leaking these data into your web pages.
If you use HTML::Template
, you use the associate method when you load the template:
$self->load_template(
'template.tmpl',
'associate' => $self->conf,
);
If you use Template::Toolkit
(via the CGI::Application::Plugin::TT
module), you can accomplish the same thing by providing a custom tt_pre_process method:
sub tt_pre_process {
my $self = shift;
my $template = shift;
my $template_params = shift;
my $config = $self->conf->getall
foreach (keys %$config) {
unless (exists $template_params->{$_}) {
$template_params->{$_} = $config->{$_};
}
}
}
METHODS
init
Initializes the plugin. The only required parameter is a config file:
$self->conf->init(
-ConfigFile => 'app.conf',
);
The other paramters are described below:
- -ConfigFile
-
The path to the configuration file to be parsed.
- -Options
-
Any additional
Config::General::Match
options. See the documentation toConfig::General
andConfig::General::Match
for more details. - -CacheConfigFiles
-
Whether or not to cache configuration files. Enabled, by default. This option is only really useful in a persistent environment such as
mod_perl
. SeeConfig File Caching
,ADVANCED USAGE
, below. - -StatConfig
-
If config file caching is enabled, this option controls how often the config files are checked to see if they have changed. The default is 60 seconds. This option is only really useful in a persistent environment such as
mod_perl
. SeeConfig File Caching
,ADVANCED USAGE
, below. - -SiteSectionName
-
Change the name of the
<Site>
section to something else. For instance, to use sections named<VirtualHost>
, use:-SiteSectionName => 'VirtualHost'
- -SiteVar
-
Change the name of the
SITE_NAME
environment variable used to match against<Site>
sections. For instance To change this name toHTTP_HOST
, use:-SiteVar => 'HTTP_HOST',
- -NestingDepth
-
The number of levels deep that sections can be nested. The default is two levels deep.
See
Section Nesting
, above.
You can initialize the plugin from within your instance CGI script:
my $app = WebApp->new();
$app->conf->init(-ConfigFile => '../../config/app.conf');
$app->run();
Or you can do so from within your cgiapp_init
method within the application:
sub cgiapp_init {
my $self = shift;
$self->conf->init(
-ConfigFile => "$ENV{DOCUMENT_ROOT}/../config/app.conf"
);
}
getall
Gets the entire configuration as a hash or hashref:
my %config = $self->conf->getall; # as hash
my $config = $self->conf->getall; # as hashref
Note that the following two method calls will return different results:
my $config = $self->conf->getall; # parsed config
my $config = $self->conf->obj->getall; # raw config
In the first case, the matching based on URI, Module, etc. has already been performed. In the second case, you are accessing the raw config with all of the <Location>
, <App>
, etc. sections intact.
param
Allows you to retrieve individual values from the configuration.
It behvaves like the <param> method in other classes, such as CGI
, CGI::Application
and HTML::Template
:
$value = $self->conf->param('some_key');
@all_keys = $self->conf->param();
obj
Provides access to the underlying Config::General::Match> object.
You can access the raw unparsed configuration data by calling
my $config = $self->conf->obj->getall; # raw config
See the note under getall
, above.
In future versions of this module, certain caching strategies may prevent you from accessing the underlying Config::General::Match object.
get_current_config ($name)
This is a class method which returns the current configuration object.
my $conf = CGI::Application::Plugin::Config::General->get_current_config;
print $conf->{'title'};
my %db_conf = CGI::Application::Plugin::Config::General->get_current_config('db');
print $db_conf{'username'};
This method is most useful in situations where you don't have access to the CGI::Application
object, such within a Class::DBI
class. See Access to Configuration information from another Class
for an example.
Note that get_current_config
returns the configuration hash (or hashref) directly. It is the equivalent of calling $self->conf->getall
.
ADVANCED USAGE
Usage in a Persistent Environment such as mod_perl
The following sections describe some notes about running this module under mod_perl:
Config File Caching
By default each config file is read only once when the conf object is first initialized. Thereafter, on each init, the cached config is used. If enough time has passed (sixty seconds by default) the config file is checked to see if it has changed. If it has changed, then the file is reread.
If you are using Config::General
version 2.28 or greater, then you can safely use the include
feature of Config::General
and all included files will be checked for changes along with the main file.
To disable caching of config files pass a false value to the -CacheConfigFiles
parameter to init, e.g:
$self->conf->init(
-ConfigFile => 'app.conf',
-CacheConfigFiles => 0,
);
To change how often config files are checked for changes, change the value of the -StatConfig
paramter to init, e.g.:
$self->conf->init(
-ConfigFile => 'app.conf',
-StatConfig => 1, # check the config file every second
);
PerlSetVar instead of SetEnv
For a (slight) performance improvement, you can use PerlSetVar
instead of SetEnv
within a <<VirtualHost
> >:
# httpd.conf
<VirtualHost _default_:8080>
PerlSetVar SITE_NAME REDSITE
</VirtualHost>
Notes on Site Matching
Renaming <Site>
or SITE_NAME
Normally, the environment variable SITE_NAME
is matched to <Site>
and <SiteMatch>
sections.
You can change these with the -SiteSectionName
and -SiteVar
parameters to init
:
$self->conf->init(
-ConfigFile => 'app.conf',
-SiteSectionName => 'Host',
-SiteVar => 'MY_HOST',
);
This will match the environment variable MY_HOST
to the sections <Host>
and <HostMatch>
.
Setting SITE_NAME
from an .htaccess
file or the CGI script
Since SITE_NAME
is just an environment variable, you can set it anywhere you can set environment variables. For instance in an .htaccess
file:
# .htaccess
SetEnv SITE_NAME bookshop
Or even the calling CGI script:
#!/usr/bin/perl
use MySite::WebApp;
$ENV{'SITE_NAME'} = 'recordshop';
my $app = MySite::WebApp->new();
$app->run();
Access to Configuration information from another Class
You can also get at the current configuration settings from a completely unrelated Perl module. This can be useful for instance if you need to configure a set of Class::DBI
classes, and you want them to be able to pick up their configuration on their own. For instance:
# app.conf
<database>
connect_string = dbi:Pg:dbname=example
username = test
password = test
<options>
RaiseError = 1
AutoCommit = 1
</options>
</database>
# In your Class::DBI subclass
package My::Class::DBI::Base;
use base 'Class::DBI';
sub db_Main {
my $conf = CGI::Application::Plugin::Config::General->get_current_config;
my $dsn = $conf->{'database'}{'connect_string'};
my $user = $conf->{'database'}{'username'};
my $pass = $conf->{'database'}{'password'};
my $opts = $conf->{'database'}{'options'};
return DBI->connect_cached($dsn, $user, $pass, $opts);
}
For this example to work, you need to make sure you call $self-
conf->init> before you access the database through any of your Class::DBI
objects.
Note that get_current_config
returns the configuration hash (or hashref) directly. is the equivalent of calling $self->conf->getall
.
Changing Parsing Behaviour Using Custom -MatchSections
Internally, this module uses Config::General
and Config::General::Match
to parse its config files. If you want to change the parsing behaviour, you can pass your own -MatchSections
list to init
. For instance, if you want to allow only sections named <URL>
, with no nesting, and have these matched exactly to the complete request path, you could do the following:
# app.conf
admin_area = 0
user_area = 0
<URL /cgi-bin/admin.cgi>
admin_area = 1
</URL>
<URL /cgi-bin/user.cgi>
user_area = 1
</URL>
# in your cgiapp_init:
$self->conf->init(
-ConfigFile => 'app.conf',
-NestingDepth => 1,
-Options => {
-MatchSections => [
{
-Name => 'URL',
-MatchType => 'exact',
-MergePriority => 0,
-SectionType => 'path',
},
]
}
);
For reference, here is the default -MatchSections
:
-MatchSections => [
{
-Name => 'Site', # overridden by -SiteSectionName
-MatchType => 'exact',
-MergePriority => 0,
-SectionType => 'env',
},
{
-Name => 'AppMatch',
-MatchType => 'regex',
-SectionType => 'module',
-MergePriority => 1,
},
{
-Name => 'App',
-MatchType => 'path',
-PathPathSeparator => '::',
-SectionType => 'module',
-MergePriority => 1,
},
{
-Name => 'LocationMatch',
-MatchType => 'regex',
-SectionType => 'path',
-MergePriority => 3,
},
{
-Name => 'Location',
-MatchType => 'path',
-SectionType => 'path',
-MergePriority => 3,
},
],
For each section, the -SectionType
param indicates what runtime variable the section will be matched against. Here are the allowed values
env: matched to the environment variable SITE_NAME (overridden by -SiteNameVar)
module: name of the Perl Module handling this request (e.g. MyApp::Users)
path: path of the request, including path_info (e.g. /cgi-bin/myapp/users.cgi/some/path)
You can use the above -SectionType
values in your own custom -MatchSection
.
AUTHOR
Michael Graham, <mag-perl@occamstoothbrush.com>
BUGS
Please report any bugs or feature requests to bug-cgi-application-plugin-config-general@rt.cpan.org
, or through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
ACKNOWLEDGEMENTS
This module would not be possible without Thomas Linden's excellent Config::General
module.
Thanks to the excellent examples provided by the other CGI::Application
plugin authors: Mark Stosberg, Michael Peters, Cees Hek and others.
SEE ALSO
CGI::Application
Config::General
Config::General::Match
CGI::Application::Plugin::Config::Simple
CGI::Application::Plugin::ConfigAuto
COPYRIGHT & LICENSE
Copyright 2005 Michael Graham, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.