CGI::Application::Plugin::Config::Context - Hierarchical, context-based configuration support for CGI::Application
Version 0.18
In your CGI::Application-based module:
use base 'CGI::Application'; use CGI::Application::Plugin::Config::Context; sub cgiapp_init { my $self = shift; # Set config file and other options $self->conf->init( file => 'app.conf', driver => 'ConfigGeneral', ); } sub my_run_mode { my $self = shift; # get entire configuration my %conf = $self->conf->context; # get entire configuration (as a reference) my $conf = $self->conf->context; # get single config parameter my $value = $self->conf->param('some_value'); # get raw configuraion (pre-context-matching) my $raw_config = $self->conf->raw; my %raw_config = $self->conf->raw; }
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'
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>
Supports any configuration format supported by Config::Context. As of this writing, that includes the following formats:
Apache-style syntax, via Config::General:
<AppMatch ^MyApp::Admin> admin_area = 1 title = Admin Area </AppMatch> <Location /cgi-bin/feedback.cgi> title = Feedback Form </Location>
XML, via XML::Simple:
<AppMatch name="^MyApp::Admin"> <admin_area>1</admin_area> <title>Admin Area</title> </AppMatch> <Location name="/cgi-bin/feedback.cgi"> <title>Feedback Form</title> </Location>
Config::Scoped syntax:
AppMatch '^MyApp::Admin' { admin_area = 1 title = Admin Area } Location '/cgi-bin/feedback.cgi' { title = Feedback Form }
Most of the examples in this document are in Config::General syntax, but can be translated into the other formats fairly easily. For more information, see the Config::Context docs.
This module allows you to easily access configuration data stored in any of the formats supported by Config::Context: Config::General (Apache style), XML::Simple and Config::Scoped.
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 (for instance) <Location> and <LocationMatch> sections.
<Location>
<LocationMatch>
You can also select configuration sections based on Virtual Host or by an environment variable you set in an .htaccess file. This allows you to share a configuration file and an 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.
.htaccess
This module provides a conf method to your CGI::Application object. First, you initialize the configuration system (typically in your cgiapp_init method):
conf
cgiapp_init
$self->conf->init( file => 'app.conf', driver => 'ConfigGeneral', );
The configuration file is parsed at this point and the configuration is available from this moment on.
Then, within your run-modes you can retrieve configuration data:
# get entire configuration my %conf = $self->conf->context; my $value = $conf{'some_value'}; # get entire configuration (as a reference) my $conf = $self->conf->context; my $value = $conf->{'some_value'}; # get single config parameter my $value = $self->conf->param('some_value');
The context method provides the configuration based on the context of your application, i.e. after matching configuration sections based on runtime data such as the current URL or package name.
context
But you can also access the raw configuration data from before the matching took place:
# get raw configuration my %conf = $self->conf->raw; # get raw configuration (as a reference) my $conf = $self->conf->raw;
You can use more than one configuration by providing a name to the conf method:
$self->conf('database')->init( file => 'db.conf', driver => 'ConfigGeneral', ); $self->conf('application')->init( file => 'app.conf', driver => 'ConfigScoped', ); ... my %db_config = $self->conf('database')->context; my %app_config = $self->conf('application')->context;
Within your configuration file, you can provide different configurations depending on the current URL, or on the package name of your application.
Matches against the SITE_NAME environment variable, using an exact match.
SITE_NAME
You can name your sections something other than <Site>, and you can use a different environment variable than SITE_NAME. See "Notes on Site Matching", below.
<Site>
Matches the Package name of your application module, for instance:
<App ABC_Books::Admin> ... </App>
The match is performed hierarchically, 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 Site::Admin> ... </App>
the packages Site::Admin and Site::Admin::Users would match, but the packages My::Site::Admin and Site::Administrative would not.
Site::Admin
Site::Admin::Users
My::Site::Admin
Site::Administrative
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 Site::Admin> ... </AppMatch>
The following packages would all match: Site::Admin, Site::Admin::Users, My::Site::Admin, MySite::Admin, Site::Administrative.
MySite::Admin
Matches hierarchically against the request URI, including the path and the PATH_INFO components, but excluding the scheme, host, port and query string.
PATH_INFO
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/
Internally, the location is obtained by calling the url method of the query object (which is usually either a CGI or CGI::Simple object):
url
$path = $webapp->query->url('-absolute' => 1, '-path_info' => 1);
Matches against the request URI, using a regular expression.
The sections are matched in the following order:
Site: <Site> 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.
<App>
<AppMatch>
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, and that URIs are more specific than Module names.
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. This alows for Location sections within Site sections and vice versa. You can change this by setting the nesting_depth parameter to init.
Location
Site
Note: there is limited support for this kind of nesting when using Config::Scoped format files. See the documentation in Config::Context::ConfigScoped for details.
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 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->context foreach (keys %$config) { unless (exists $template_params->{$_}) { $template_params->{$_} = $config->{$_}; } } }
NOTE: If you plan to merge data directly from your config files to your templates, 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.
Initializes the plugin. The only required parameter is the source of the configuration, either file, string or hash.
file
string
hash
$self->conf->init( file => 'app.conf', );
The other paramters are described below:
The path to the configuration file to be parsed.
A string containing configuration data to be parsed.
A Perl data structure containing containing the pre-parsed config data.
Which Config::Context driver should parse the config. Currently supported drivers are:
driver module name ------ ----------- ConfigGeneral Config::Context::ConfigGeneral ConfigScoped Config::Context::ConfigScoped XMLSimple Config::Context::XMLSimple
The default driver is ConfigGeneral.
ConfigGeneral
Options to pass directly on to the driver. This is a multi-level hash, where the top level keys are the driver names:
my $conf = Config::Context->new( driver => 'ConfigScoped', driver_options => { ConfigGeneral => { -AutoLaunder => 1, }, ConfigScoped = > { warnings => { permissions => 'off', } }, }, );
In this example the options under ConfigScoped will be passed to the ConfigScoped driver. (The options under ConfigGeneral will be ignored because driver is not set to 'ConfigGeneral'.)
ConfigScoped
driver
'ConfigGeneral'
Whether or not to cache configuration files. Enabled, by default. This option is useful in a persistent environment such as mod_perl. See "Config File Caching" under "ADVANCED USAGE", below.
mod_perl
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 useful in a persistent environment such as mod_perl. See "Config File Caching" under ADVANCED USAGE, below.
ADVANCED USAGE
Change the name of the <Site> section to something else. For instance, to use sections named <VirtualHost>, use:
<VirtualHost>
site_section_name => 'VirtualHost'
Change the name of the SITE_NAME environment variable used to match against <Site> sections. For instance To change this name to HTTP_HOST, use:
HTTP_HOST
site_var => 'HTTP_HOST',
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(file => '../../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( file => "$ENV{DOCUMENT_ROOT}/../config/app.conf" ); }
Gets the entire configuration as a hash or hashref:
my %config = $self->conf->context; # as hash my $config = $self->conf->context; # as hashref
Gets the raw configuration as a hash or hashref:
my %raw_config = $self->conf->raw; # as hash my $raw_config = $self->conf->raw; # as hashref
The raw configuration is the configuration before matching has taken place. It includes all the raw config with all of the <Location>, <App>, etc. sections intact.
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:
param
$value = $self->conf->param('some_key'); @all_keys = $self->conf->param();
This is a class method which returns the current configuration object.
my $conf = CGI::Application::Plugin::Config::Context->get_current_context; print $conf->{'title'}; my %db_conf = CGI::Application::Plugin::Config::Context->get_current_context('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.
Same as get_current_context, but returns the raw configuration.
The following sections describe some notes about running this module under mod_perl:
Config::Context caches configuration files 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.
This means that in a persistent environment like mod_perl, the config file is parsed on the first request, but not on subsequent requests.
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.
See the docs for Config::Context for details.
Normally, the environment variable SITE_NAME is matched to <Site> section.
You can change these with the site_section_name and site_var parameters to init:
$self->conf->init( file => 'app.conf', site_section_name => 'Host', site_var => 'MY_HOST', );
This will match the environment variable MY_HOST to the <Host> section.
MY_HOST
<Host>
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();
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::Context->get_current_context; 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.
$self->conf->init
You can also call get_current_raw_config to get access to the raw configuration.
Internally, this module uses Config::Context to parse its config files. If you want to change the parsing behaviour, you can pass your own match_sections 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:
<URL>
# 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( file => 'app.conf', nesting_depth => 1, match_sections => [ { name => 'URL', match_type => 'exact', merge_priority => 0, section_type => 'path', }, ] );
For reference, here is the default match_sections:
[ { name => 'Site', # overridden by 'site_section_name' match_type => 'exact', merge_priority => 0, section_type => 'env', }, { name => 'AppMatch', match_type => 'regex', section_type => 'module', merge_priority => 1, }, { name => 'App', match_type => 'path', path_separator => '::', section_type => 'module', merge_priority => 1, }, { name => 'LocationMatch', match_type => 'regex', section_type => 'path', merge_priority => 3, }, { name => 'Location', match_type => 'path', section_type => 'path', merge_priority => 3, }, ],
For each section, the section_type 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 site_name_var) 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 section_type values in your own custom match_sections.
For more information on the syntax of match_sections, see the docs for Config::Context.
If you want to access the features of this module using a method other than conf, you can do so via Anno Siegel's Exporter::Renaming module (available on CPAN).
use Exporter::Renaming; use CGI::Application::Plugin::Config::Context Renaming => [ conf => custom_config_method]; sub cgiapp_init { my $self = shift; # Set config file and other options $self->custom_config_method->init( file => 'app.conf', driver => 'ConfigGeneral', ); my $config = $self->custom_config_method->context; # .... }
Michael Graham, <mag-perl@occamstoothbrush.com>
<mag-perl@occamstoothbrush.com>
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.
bug-cgi-application-plugin-config-general@rt.cpan.org
Thanks to the excellent examples provided by the other CGI::Application plugin authors: Mark Stosberg, Michael Peters, Cees Hek and others.
CGI::Application Config::Context Config::Context::ConfigGeneral Config::Context::ConfigScoped Config::Context::XMLSimple CGI::Application::Plugin::Config::Simple CGI::Application::Plugin::ConfigAuto Exporter::Renaming CGI::Application::Plugin::TT Template::Toolkit HTML::Template
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.
To install CGI::Application::Plugin::Config::Context, copy and paste the appropriate command in to your terminal.
cpanm
cpanm CGI::Application::Plugin::Config::Context
CPAN shell
perl -MCPAN -e shell install CGI::Application::Plugin::Config::Context
For more information on module installation, please visit the detailed CPAN module installation guide.