<head>
<title>CGI::WebToolkit - Website Toolkit</title>
<link rel="stylesheet" href="POD_CPAN.css" type="text/css" />
<link rev="made" href="mailto:root@b07.apple.com" />
</head>
<body>
<p><a name="__index__"></a></p>
<!-- INDEX BEGIN -->
<ul>
<li><a href="#name">NAME</a></li>
<li><a href="#synopsis">SYNOPSIS</a></li>
<li><a href="#description">DESCRIPTION</a></li>
<ul>
<li><a href="#directory_structure">Directory structure</a></li>
<li><a href="#constructor_new__">Constructor <code>new()</code></a></li>
<ul>
<li><a href="#required_settings">Required settings</a></li>
<ul>
<li><a href="#publicpath____path">-publicpath => <em>path</em></a></li>
<li><a href="#publicurl____url">-publicurl => <em>url</em></a></li>
<li><a href="#privatepath____path">-privatepath => <em>path</em></a></li>
<li><a href="#cgipath____path">-cgipath => <em>path</em></a></li>
<li><a href="#cgiurl____url">-cgiurl => <em>url</em></a></li>
</ul>
<li><a href="#optional_settings">Optional settings</a></li>
<ul>
<li><a href="#config____filename">-config => <em>filename</em></a></li>
<li><a href="#engine____databasetype">-engine => <em>database-type</em></a></li>
<li><a href="#user____name">-user => <em>name</em></a></li>
<li><a href="#name____databasename">-name => <em>database-name</em></a></li>
<li><a href="#password____password">-password => <em>password</em></a></li>
<li><a href="#host____host">-host => <em>host</em></a></li>
<li><a href="#port____port">-port => <em>port</em></a></li>
<li><a href="#templatefallbacks______name_______">-templatefallbacks => [ <em>name</em>, ... ]</a></li>
<li><a href="#idparam____name">-idparam => <em>name</em></a></li>
<li><a href="#sessiontable____name">-sessiontable => <em>name</em></a></li>
<li><a href="#sessiontimeout____seconds">-sessiontimeout => <em>seconds</em></a></li>
<li><a href="#usertable____name">-usertable => <em>name</em></a></li>
<li><a href="#accessconfig____name">-accessconfig => <em>name</em></a></li>
<li><a href="#cachetable____name">-cachetable => <em>name</em></a></li>
<li><a href="#allowclearcache____1_0">-allowclearcache => 1/0</a></li>
<li><a href="#clearcacheparam____name">-clearcacheparam => <em>name</em></a></li>
<li><a href="#workflowparam____name">-workflowparam => <em>name</em></a></li>
<li><a href="#entryaction____name">-entryaction => <em>name</em></a></li>
<li><a href="#modules______name_______">-modules => [ <em>name</em>, ... ]</a></li>
<li><a href="#cssfiles______name_______">-cssfiles => [ <em>name</em>, ... ]</a></li>
<li><a href="#jsfiles______name_______">-jsfiles => [ <em>name</em>, ... ]</a></li>
<li><a href="#phrasetable_____name_">-phrasetable => <name></a></li>
<li><a href="#defaultlanguage____language">-defaultlanguage => <em>language</em></a></li>
<li><a href="#onsessionstart____functionname">-onsessionstart => <em>functionname</em></a></li>
<li><a href="#allowmacros____1_0">-allowmacros => 1/0</a></li>
<li><a href="#uploadmaxsize____bytes">-uploadmaxsize => <em>bytes</em></a></li>
</ul>
</ul>
<li><a href="#objectoriented_and_functional_style">Objectoriented and functional style</a></li>
<li><a href="#methods_for_workflow_abstraction">Methods for workflow abstraction</a></li>
<ul>
<li><a href="#handle__"><code>handle()</code></a></li>
<li><a href="#call__"><code>call()</code></a></li>
<li><a href="#output__"><code>output()</code></a></li>
<li><a href="#followup__"><code>followup()</code></a></li>
<li><a href="#getparam__"><code>getparam()</code></a></li>
<li><a href="#fail__"><code>fail()</code></a></li>
<li><a href="#shortcut_syntax_for_calling_module_functions">Shortcut Syntax for calling module functions</a></li>
</ul>
<li><a href="#methods_for_session_management">Methods for session management</a></li>
<ul>
<li><a href="#get__"><code>get()</code></a></li>
<li><a href="#set__"><code>set()</code></a></li>
<li><a href="#unset__"><code>unset()</code></a></li>
</ul>
<li><a href="#methods_for_template_management">Methods for template management</a></li>
<ul>
<li><a href="#fill__"><code>fill()</code></a></li>
<li><a href="#template_names_and_themes">Template names and themes</a></li>
<li><a href="#generator_functions">Generator functions</a></li>
<li><a href="#common_template_placeholders">Common template placeholders</a></li>
<li><a href="#default_placeholder_values">Default placeholder values</a></li>
<li><a href="#simplified_calling_of_fill__">Simplified calling of <code>fill()</code></a></li>
<li><a href="#template_macros">Template Macros</a></li>
</ul>
<li><a href="#methods_for_database_access">Methods for database access</a></li>
<ul>
<li><a href="#find__"><code>find()</code></a></li>
<li><a href="#create__"><code>create()</code></a></li>
<li><a href="#update__"><code>update()</code></a></li>
<li><a href="#remove__"><code>remove()</code></a></li>
<li><a href="#query__"><code>query()</code></a></li>
<li><a href="#load__"><code>load()</code></a></li>
</ul>
<li><a href="#methods_for_user_and_rights_management">Methods for user and rights management</a></li>
<ul>
<li><a href="#login__"><code>login()</code></a></li>
<li><a href="#logout__"><code>logout()</code></a></li>
<li><a href="#allowed__"><code>allowed()</code></a></li>
</ul>
<li><a href="#methods_for_internationalization">Methods for Internationalization</a></li>
<ul>
<li><a href="#___"><code>_()</code></a></li>
<li><a href="#lang__"><code>lang()</code></a></li>
<li><a href="#translate__"><code>translate()</code></a></li>
</ul>
<li><a href="#methods_for_form_file_upload">Methods for form file upload</a></li>
<ul>
<li><a href="#upload__"><code>upload()</code></a></li>
</ul>
<li><a href="#other_methods">Other methods</a></li>
<ul>
<li><a href="#logmsg__"><code>logmsg()</code></a></li>
</ul>
<li><a href="#predefined_template_functions">Predefined template functions</a></li>
<li><a href="#fileformats">Fileformats</a></li>
<ul>
<li><a href="#configuration_file_format">Configuration file format</a></li>
<li><a href="#template_file_format">Template file format</a></li>
</ul>
</ul>
<li><a href="#export">EXPORT</a></li>
<li><a href="#see_also">SEE ALSO</a></li>
<li><a href="#author">AUTHOR</a></li>
<li><a href="#copyright_and_license">COPYRIGHT AND LICENSE</a></li>
</ul>
<!-- INDEX END -->
<hr />
<p>
</p>
<h1><a name="name">NAME</a></h1>
<p>CGI::WebToolkit - Website Toolkit</p>
<p>
</p>
<hr />
<h1><a name="synopsis">SYNOPSIS</a></h1>
<pre>
use CGI::WebToolkit;
my $wtk = CGI::WebToolkit->new( %options );
print $wtk->handle();</pre>
<p>
</p>
<hr />
<h1><a name="description">DESCRIPTION</a></h1>
<p>CGI::WebToolkit tries to simplify the common tasks when creating dynamic
websites. The use of CGI::WebToolkit should lead to the development of easy
to understand, relieable and fast dynamic web applications that
are easy to adjust and maintain.</p>
<p>CGI::WebToolkit itself is designed to be as simple and straight
forward as possible. The basic philosophy behind the module is
best described as ``Do not repeat yourself.'' (DNRY). The experience
gained while developing a number of websites has led to certain
common recipes that are packaged as a single module for reusability.</p>
<p>CGI::WebToolkit was writted to provide abstractions and functionality for the
following common tasks in web application development:</p>
<ol>
<li><strong><a name="item_configuration">Configuration</a></strong><br />
</li>
<li><strong><a name="item_abstraction">Workflow abstraction (aka runlevel, modes, actions, ...)</a></strong><br />
</li>
<li><strong><a name="item_sessions">Sessions</a></strong><br />
</li>
<li><strong><a name="item_templates">Templates (incl. form creation etc.)</a></strong><br />
</li>
<li><strong><a name="item_datenbase_abstraction">Datenbase abstraction</a></strong><br />
</li>
<li><strong><a name="item_user_and_rights_management">User and rights management</a></strong><br />
</li>
<li><strong><a name="item_internationalization">Internationalization</a></strong><br />
</li>
<li><strong><a name="item_caching">Caching</a></strong><br />
</li>
</ol>
<p>
</p>
<h2><a name="directory_structure">Directory structure</a></h2>
<p>CGI::WebToolkit relies on a common directory structure. This structure makes it
possible to simplify the configuration of the application to a level
where only the minimal information needed must be given. This makes
development more relieble, faster and other tools may work on many
websites.</p>
<p>The directory structure of the <strong>public directory</strong> as required
by CGI::WebToolkit, usually this would go somewhere in the htdocs directory
on the server:</p>
<pre>
themes/
<themename>/</pre>
<p>The directory structure of the <strong>private directory</strong> as required by
CGI::WebToolkit, usually this would go <strong>outside</strong> of the web-accessable area
on the server:</p>
<pre>
acls/
cacheconfigs/
configs/
generators/
javascripts/
logs/
modules/
schemas/
styles/
templates/
<themename>/
workflows/</pre>
<p>The directory structure of the <strong>cgi directory</strong> can have any form.
Usually this resembles the cgi directory on the server. The actual
application scripts go there.</p>
<p>
</p>
<h2><a name="constructor_new__">Constructor <code>new()</code></a></h2>
<p>The constructor takes only named parameters, of which some are optional.
These options are given in a shell-like syntax, e.g <em>-optname</em>.
The case of the parameter name does not matter, so you can either write
<em>-OptName</em>, <em>-optName</em>, <em>optname</em> or any kind of other case variation.</p>
<pre>
use CGI::WebToolkit;
my $wtk = CGI::WebToolkit->new(
# required
-publicpath => '...',
-publicurl => '...',
-privatepath => '...',
-cgipath => '...',
-cgiurl => '...',
# optional
# ...
);</pre>
<p>
</p>
<h3><a name="required_settings">Required settings</a></h3>
<p>
</p>
<h4><a name="publicpath____path">-publicpath => <em>path</em></a></h4>
<p>The path to the <strong>public directory</strong> of the web application.</p>
<p>
</p>
<h4><a name="publicurl____url">-publicurl => <em>url</em></a></h4>
<p>The url to the <strong>public directory</strong> of the web application.</p>
<p>
</p>
<h4><a name="privatepath____path">-privatepath => <em>path</em></a></h4>
<p>The path to the <strong>private directory</strong> of the web application.</p>
<p>
</p>
<h4><a name="cgipath____path">-cgipath => <em>path</em></a></h4>
<p>The path to the <strong>cgi directory</strong> of the web application.</p>
<p>
</p>
<h4><a name="cgiurl____url">-cgiurl => <em>url</em></a></h4>
<p>The url to the <strong>cgi directory</strong> of the web application.</p>
<p>
</p>
<h3><a name="optional_settings">Optional settings</a></h3>
<p>
</p>
<h4><a name="config____filename">-config => <em>filename</em></a></h4>
<p>This is the name of a configuration file to load. The file should
exist in the <em>config</em> directory. Values from configuration
files have low priority, any parameter that is set directly within
the <code>new()</code> call overwrites the config value.</p>
<p>
</p>
<h4><a name="engine____databasetype">-engine => <em>database-type</em></a></h4>
<p>The name of the database engine, default is <em>mysql</em>.</p>
<p>
</p>
<h4><a name="user____name">-user => <em>name</em></a></h4>
<p>The name of the database user, default is <em>guest</em>.</p>
<p>
</p>
<h4><a name="name____databasename">-name => <em>database-name</em></a></h4>
<p>The name of the database to use, default is empty.</p>
<p>
</p>
<h4><a name="password____password">-password => <em>password</em></a></h4>
<p>The password of the database user, default is empty.</p>
<p>
</p>
<h4><a name="host____host">-host => <em>host</em></a></h4>
<p>The host name for the database server, default is <em>localhost</em>.</p>
<p>
</p>
<h4><a name="port____port">-port => <em>port</em></a></h4>
<p>The port number for the database server, default is empty.</p>
<p>
</p>
<h4><a name="templatefallbacks______name_______">-templatefallbacks => [ <em>name</em>, ... ]</a></h4>
<p>The fallback directories that are searched for the template files.
The first one is searched first, then the second etc. until
the template file is found. If no template file could be found,
the template <em>core.error</em> is used.</p>
<p>
</p>
<h4><a name="idparam____name">-idparam => <em>name</em></a></h4>
<p>The name of the POST/GET parameter that holds the session id,
default is <em>sid</em>.</p>
<p>
</p>
<h4><a name="sessiontable____name">-sessiontable => <em>name</em></a></h4>
<p>The name of the database table that holds the session data.
The table must contain these columns: <em>id</em>, <em>session_id</em>, <em>content</em>
and <em>last_update</em>. The default table name is <em>session</em>.</p>
<p>An example SQL statement (for MySQL) that will create an appropriate
database session table:</p>
<pre>
create table `session` (
`id` int not null auto_increment primary key,
`session_id` varchar(32),
`content` text,
`last_update` int(16)
);</pre>
<p>To deactivate sessions, leave this option empty, which is also
the default.</p>
<p>
</p>
<h4><a name="sessiontimeout____seconds">-sessiontimeout => <em>seconds</em></a></h4>
<p>The number of seconds after which a session is regarded as trash
and not available anymore. Default timeout is <em>1800 seconds</em> (<em>30 minutes</em>).</p>
<p>
</p>
<h4><a name="usertable____name">-usertable => <em>name</em></a></h4>
<p>Name of the database table to store user info in.
An example SQL statement (for MySQL) that will create an appropriate
database user table:</p>
<pre>
create table `user` (
`id` int not null auto_increment primary key,
`loginname` varchar(255),
`password` varchar(32),
`language` varchar(5)
);</pre>
<p>If you do not need this feature, just leave the tablename empty,
which is also the default.</p>
<p>
</p>
<h4><a name="accessconfig____name">-accessconfig => <em>name</em></a></h4>
<p>This option defined what access configuration file is used.
The default is empty, which means that no access check will be
performed.</p>
<p>
</p>
<h4><a name="cachetable____name">-cachetable => <em>name</em></a></h4>
<p>The name of the database table that is used to store cached
results from workflow functions. In order to make the cache work
properly you have to define cache parameters (see <em>Caching</em>).</p>
<p>An example SQL statement (for MySQL) that will create an appropriate
database cache table:</p>
<pre>
create table `cache` (
`id` int not null auto_increment primary key,
`hash` varchar(32),
`content` text,
`last_update` int(16)
);</pre>
<p>To deactivate caching, leave the tablename empty, which is also
the default.</p>
<p>
</p>
<h4><a name="allowclearcache____1_0">-allowclearcache => 1/0</a></h4>
<p>Caching is activated, as soon as you define a cachetable inside
the configuration variables, s.a. But how do you delete the cache,
e.g. for testing purposes? If this option is set to 1 (the default),
you only have to attach an additional parameter to the url named
``clearcache'' and the whole cache will be removed from the database.</p>
<p>This method clears all cache entries in the configured cache
table. It is currently impossible to selectively remove only
certain cache entries, because the cache entry's name (a hash
value) cannot be used to determine any details, about where
this entry is from, e.g. the name of the workflow function etc.</p>
<p>
</p>
<h4><a name="clearcacheparam____name">-clearcacheparam => <em>name</em></a></h4>
<p>The name of the POST/GET parameter that triggers the removal
of the cache, if activated, see -allowclearcache.</p>
<p>
</p>
<h4><a name="workflowparam____name">-workflowparam => <em>name</em></a></h4>
<p>The name of the POST/GET parameter that holds the name of the
workflow function, default is <em>do</em>.</p>
<p>
</p>
<h4><a name="entryaction____name">-entryaction => <em>name</em></a></h4>
<p>The name of the workflow function that is called if no workflow
function name could be determined, default is <em>core.default</em>.</p>
<p>
</p>
<h4><a name="modules______name_______">-modules => [ <em>name</em>, ... ]</a></h4>
<p>The names of modules to load. These modules will be available
from inside the workflow functions. Modules such as these usually
contain general functions that return arbitrary data in order
to calculate, deliver or store other data. The modules must exist
somewhere in @INC or inside the <em>modules</em> directory.</p>
<p>
</p>
<h4><a name="cssfiles______name_______">-cssfiles => [ <em>name</em>, ... ]</a></h4>
<p>The names of css files that are all combined into one single css.
The final css can be retrieved via the special url <em>...?to=core.combine.css</em>
The css files must exist inside the <em>styles</em> directory.</p>
<p>
</p>
<h4><a name="jsfiles______name_______">-jsfiles => [ <em>name</em>, ... ]</a></h4>
<p>The names of javascript files that are all combined into one single javascript.
The final javascript can be retrieved via the special url <em>...?to=core.combine.js</em>
The javascript files must exist inside the <em>javascript</em> directory.</p>
<p>
</p>
<h4><a name="phrasetable_____name_">-phrasetable => <name></a></h4>
<p>The name of the database table to use for the translation dictionary.</p>
<p>An example SQL statement (for MySQL) that will create an appropriate
database dictionary table:</p>
<pre>
create table `phrase` (
`id` int not null auto_increment primary key,
`language` varchar(5) not null,
`name` varchar(32),
`translations` text
);</pre>
<p>To deactivate the translation feature, just leave the tablename empty,
which is also the default.</p>
<p>
</p>
<h4><a name="defaultlanguage____language">-defaultlanguage => <em>language</em></a></h4>
<p>The language used for guests that come to the website for
the first time and are not currenlty logged in.</p>
<p>
</p>
<h4><a name="onsessionstart____functionname">-onsessionstart => <em>functionname</em></a></h4>
<p>The name of the workflow function that is called when the session
is started. This may be useful to initialize some session variables.
The result of that workflow function is then ignored.</p>
<p>
</p>
<h4><a name="allowmacros____1_0">-allowmacros => 1/0</a></h4>
<p>If this option is set to 1 (default), the templates that are
loaded, are filtered through a macro processor. It is basicly
a processor that allows the loading of templates from within
(xml-based) templates. Disabling this feature makes processing
of template a bit faster.</p>
<p>See separate section <em>macros</em> below for details on macros.</p>
<p>
</p>
<h4><a name="uploadmaxsize____bytes">-uploadmaxsize => <em>bytes</em></a></h4>
<p>Maximum allowed upload size. This is the internal limit, there
is usually a server limit for uploads, which probably has
to be adjusted as well. The default size is 6MB.</p>
<p>
</p>
<h2><a name="objectoriented_and_functional_style">Objectoriented and functional style</a></h2>
<p>The methods of CGI::WebToolkit can be invoced in two different styles:
in the object oriented manner using standard syntax:</p>
<pre>
$wtk->methodname();</pre>
<p>and in a functional manner:</p>
<pre>
methodname();</pre>
<p>When called as usual functions, the CGI::WebToolkit instance the call works on
is a singleton and refers to the last instance of CGI::WebToolkit that was
created via the <code>new()</code> constructor.</p>
<p>The functional way of invocation has the advantage of beeing
visually more obvious. Usually there is only one instance of CGI::WebToolkit
anyway, so conflicts hardly happen.</p>
<p>
</p>
<h2><a name="methods_for_workflow_abstraction">Methods for workflow abstraction</a></h2>
<p>In CGI::WebToolkit, each time a webpage is requested, the workflow engine tries
to determine, which workflow function should be executed. Then this
function is executed. Workflow functions are ordinary Perl functions
that get certain parameters and return an array of values. Each
workflow function has a unique name and can be sorted into categories
and/or subcategories etc.</p>
<p>
</p>
<h3><a name="handle__"><code>handle()</code></a></h3>
<p>This method is used to handle the current request. It will determine
the workflow function to be called, call it, analyse its result
and call other workflow functions if nessessary. Finally, it will
return a string - the webpage requested, a part of a webpage
or a valid replacement, such as an error page.</p>
<p><code>handle()</code> will analyse the workflow parameters that were
given to the request from the client and based on that call a certain
workflow function. If this function does return a <em>followup</em>, it
will be called directly afterwards, if not, the message returned by
the workflow function is returned. A <followup> is a special return
value that tells CGI::WebToolkit to forward control flow directly to another
workflow function.</p>
<p>Inside a workflow function the CGI::WebToolkit instance is magically
available as the variable $wtk and the additional arguments
are stored in @args.</p>
<p>Examples for workflow functions:</p>
<pre>
# ...
return $wtk->output(1, 'ok', "<h1>Hello, World!</h1>");</pre>
<pre>
# ...
return $wtk->followup("core.error");</pre>
<pre>
# ...
return $wtk->output(1, 'ok', "...", 'image/png');</pre>
<p>The bodies of workflow functions are stored in Perl files, one for
each function inside a directory (or subdirectory etc.) in the <em>workflows</em>
directory.</p>
<p>
</p>
<h3><a name="call__"><code>call()</code></a></h3>
<p>This method is used to call a workflow function directly and
return its result unmodified and unanalysed.</p>
<pre>
my $result = $wtk->call( $name, @args );</pre>
<p>
</p>
<h3><a name="output__"><code>output()</code></a></h3>
<p>This method returns a valid CGI::WebToolkit result that can be returned from
a workflow function. This result is used, when the workflow
function wants to return a complete page or a part of a page.
It gets the following options:</p>
<pre>
# ...
return $wtk->output(1, 'info...', $html, 'text/html');</pre>
<p>If the mimetype is not explicitly given, <em>text/html</em> is used.</p>
<p>
</p>
<h3><a name="followup__"><code>followup()</code></a></h3>
<p>This method returns a valid CGI::WebToolkit result that can be returned from
a workflow function. Its used when a workflow function wants
to silently hand over control flow to another workflow function.
It gets the following options:</p>
<pre>
# ...
return $wtk->followup('group.function', @args);</pre>
<p>
</p>
<h3><a name="getparam__"><code>getparam()</code></a></h3>
<p>The <code>getparam()</code> method is used to return a parameter, match it
against a regular expression or return a default value if no
parameter was set in neither POST nor GET vars.</p>
<p>Parameters:</p>
<ol>
<li><strong><a name="item__24name__3d_the_name_of_the_parameter_2e">$name = The name of the parameter.</a></strong><br />
</li>
<li><strong><a name="item__24default__3d_the_default_value_2e">$default = The default value.</a></strong><br />
</li>
<li><strong><a name="item__24regex__3d_the_regular_expression_used_to_check_">$regex = The regular expression used to check the parameter value.</a></strong><br />
</li>
</ol>
<p>
</p>
<h3><a name="fail__"><code>fail()</code></a></h3>
<p><code>fail()</code> dies hard with a short message. All control flow comes
to an end immedietly. This method can be used when some error occurs
and there is no hope of recovery. Since only the raw message will
be shown to the user, you should consider creating a complete
error page, if that is possible.</p>
<p>Example:</p>
<pre>
fail("cannot open file 'xyz'");</pre>
<p>
</p>
<h3><a name="shortcut_syntax_for_calling_module_functions">Shortcut Syntax for calling module functions</a></h3>
<p>Businesss logic usually goes into modules that are loaded using
the -modules switch, s.a. But when you call a subroutine from
such a module, e.g. inside a workflow function, its usually
a unhandy, for example:</p>
<pre>
CGI::WebToolkit::Modules::MyProjectModule::my_tiny_function($wtk, @args);</pre>
<p>Plus, in most cases, you have to pass the CGI::WebToolkit instance to the
subroutine, because you somehow need it in there.</p>
<p>To make life easier, there is an alternative, shorter way
of calling a module subroutine:</p>
<pre>
_my_tiny_function(@args);</pre>
<p>That means exactly the same as the call above. To be honest, it
means <em>almost</em> the same. Whereas with the long syntax, you
exactly know which module is used, whereas with the short syntax,
CGI::WebToolkit will try one module after another until it has found the
subroutine named <em>my_tiny_function</em> and then calls it.</p>
<p>
</p>
<h2><a name="methods_for_session_management">Methods for session management</a></h2>
<p>Session data is data that is stored on the server side and can be accessed
throughout several webpage requests. In the CGI::WebToolkit the session is a flat hash
of arbitrary data that is stored in the database or a flat file.</p>
<p>In order to identify the session, a session id is used. This session id
has to be submitted by the client for each request, either through a
cookie, a POST variable or a GET variable. The name of this variable
is usually <em>sid</em>, but can be configured. CGI::WebToolkit takes automaticly care of
that the session id is submitted via links and form submits to
the application script.</p>
<p>To group certain session data entries, usually a dot-based notation is used,
e.g. <em>my_workflow.my_name</em>. This method is stronlgy recommended as well
as limiting the amount of session entries to the absolute minimum.</p>
<p>When the CGI::WebToolkit instance is created, the session is loaded automaticly and
can be accessed through the following methods:</p>
<p>
</p>
<h3><a name="get__"><code>get()</code></a></h3>
<pre>
my $value = $wtk->get( "my_name" );</pre>
<p>
</p>
<h3><a name="set__"><code>set()</code></a></h3>
<pre>
$wtk->set( "my_name", "value" );</pre>
<p>
</p>
<h3><a name="unset__"><code>unset()</code></a></h3>
<p>This method removes the entry from the session. When you try to
retrieve the entry's value afterwards, you will get an undefined
value.</p>
<pre>
$wtk->set( "my_name" );</pre>
<p>
</p>
<h2><a name="methods_for_template_management">Methods for template management</a></h2>
<p>By definition a template is something that contains placeholders that
are replaced by actual values when the template is <em>filled</em>. In CGI::WebToolkit
a template is a function that returns any kind of string, usually
that would be XHTML or XML.</p>
<p>
</p>
<h3><a name="fill__"><code>fill()</code></a></h3>
<p>The <code>fill()</code> method fills a hash of data into a template by replacing
the placeholders inside the template with actual values. Here are
some examples for <code>fill()</code> calls:</p>
<pre>
my $name1 = 'group.subgroup.name';
my $name2 = 'othername';
my $hash = { 'title' => "...", -info => "..." };
my $string1 = $wtk->fill( $name1, $hash );
my $string2 = $wtk->fill( $name2, [ $hash, $hash ] );</pre>
<p>The first parameter to the <code>fill()</code> method is
the name of the template. See below for details on template names.</p>
<p>The second parameter to the <code>fill()</code> method is the hash with
the actual information. The values inside the hash are (usually)
all strings. If an array (reference) of multiple hashs is supplied,
the template is loaded for each hash and the final result is the
concatenation of the filled templates.</p>
<p>When the information is filled into the template, each placeholder
is replaced with the value of the key of the same name, e.g.
the hash key <em>info</em> provides the value for the placeholder <em>info</em>.
Inside the template the placeholders are usually noted inside
curly brackets. Here is an example of a template:</p>
<pre>
<h1>{title}</h1>
<p>{info}</p></pre>
<p>The hash keys can be noted in any case with an optional dash at
the beginning in order to allow easy notation, e.g. the hash
keys <em>Info</em>, <em>-info</em>, <em>-InFO</em> etc. refer to the same
placeholder <em>info</em>.</p>
<p>
</p>
<h3><a name="template_names_and_themes">Template names and themes</a></h3>
<p>In CGI::WebToolkit Themes are sets of templates. Each theme has its own subdirectory
inside the <em>templates</em> directory. These theme directories can
contain more subdirectories to group templates semantically.</p>
<p>Here some examples fof valid names and the corresponding
template files, assuming the template fallback is set to
<em>myproject</em> as the first theme and <em>core</em> as the second theme:</p>
<pre>
my $name1 = 'page'; # "<private-path>/templates/myproject/page.html"
my $name2 = 'form.text'; # "<private-path>/templates/core/form/text.html"</pre>
<p>Each dot in the name is converted to a slash to form the
final template filename. Then the fallback theme directories are
sequentially checked for a file with that name and the first
match is used as the template file.</p>
<p>If you want to load the template from a specific theme, you
can use the following syntax:</p>
<pre>
# This will load from the "core" theme
my $string1 = $wtk->fill( 'core:form.date', @data );
# This will load from the theme that is first
# defined inside the fallback hierarchy of themes
my $string2 = $wtk->fill( 'form.date', @data );</pre>
<p>
</p>
<h3><a name="generator_functions">Generator functions</a></h3>
<p>If no template could be found using the theme fallbacks declared
in the configuration (s.a.), then a generator function of that
name is called.</p>
<p>[...]</p>
<p>
</p>
<h3><a name="common_template_placeholders">Common template placeholders</a></h3>
<p>The following placeholders are always available and can therefor
be used in any template loaded with the <code>fill()</code> method:</p>
<p><strong>{script_url}</strong></p>
<p>The URL of the script executable, including the script name.</p>
<p><strong>{public_url}</strong></p>
<p>The URL of the public directory.</p>
<p><strong>{clear}</strong></p>
<p>The special XHTML snippet <div class=``clear''></div></p>
<p><strong>{do_nothing_url}</strong></p>
<p>This URL can be used in Links that should do nothing.
It containts the Javascript snippet javascript:void(1);</p>
<p><strong>{javascript_url}</strong></p>
<p>This URL points to the special core workflow function <em>core.combine.javascript</em>
and therefor points to a combined javascript.</p>
<p><strong>{css_url}</strong></p>
<p>This URL points to the special core workflow function <em>core.combine.css</em>
and therefor points to a combined stylesheet.</p>
<p>
</p>
<h3><a name="default_placeholder_values">Default placeholder values</a></h3>
<p>Any placeholders in a template that have not been filled, are
by default replaced with an empty string. Sometimes you want to
have a special default value instead of the empty string.
Example:</p>
<pre>
<b>{title:This is the default title}</b></pre>
<p>
</p>
<h3><a name="simplified_calling_of_fill__">Simplified calling of <code>fill()</code></a></h3>
<p>To make it visually clearer what template is filled, there is an
alternative way of calling the <code>fill()</code> method. The following
statements mean the same:</p>
<pre>
my $string = $wtk->fill('form.date', {-month => '...', -year => '...'});
my $string = $wtk->FormDate(-month => '...', -year => '...');</pre>
<p>Using the general method of using the functional style of
invocation, this even gets shorter:</p>
<pre>
my $string = FormDate(-month => '...', -year => '...');</pre>
<p>In case you want the template from a specific theme, use this
syntax for the functional invocation:</p>
<pre>
my $string = Core_FormDate(-month => '...', -year => '...');</pre>
<p>
</p>
<h3><a name="template_macros">Template Macros</a></h3>
<p>Template macros are a way of loading templates from within
templates.</p>
<p>For example, if you want to create a general piece of markup
that is considered ``a box'', you wish you were able to
keep this markup in one place and use it from anywhere else
in other templates. That is what these macros are for.</p>
<p>Example of a box markup:</p>
<pre>
<div class="box">
<h1>{title}</h1>
<p>{content}</p>
</div></pre>
<p>This markup goes in a file called <em>templates/my_project/box.html</em>
(in our example).</p>
<p>And here is how to use the box markup inside another template:</p>
<pre>
<h1>Hallo!</h2>
<box title="My Box">In the box.</box></pre>
<p>The macro processor allows recursive notation of macros,
so that the following works as expected:</p>
<pre>
<box>In the <box>other box</box> box.</box></pre>
<p>
</p>
<h2><a name="methods_for_database_access">Methods for database access</a></h2>
<p>To access the data that is stored inside the attached (relational) database, CGI::WebToolkit
offers some handy functions.
When the CGI::WebToolkit instance is created, all information regarding the database
connection is given and CGI::WebToolkit will try to establish a connection.</p>
<p>Internally, a DBI instance is created, so any kind of database can be
used for which a DBI driver is provided.</p>
<p>Any fieldname noted below can consist of the field's name only or addiontally
the tablename, e.g. <em>myfield</em> and <em>mytable.myfield</em> are both valid
field names.</p>
<p>
</p>
<h3><a name="find__"><code>find()</code></a></h3>
<p>To retrieve records from the database, use the <code>select()</code> method:</p>
<pre>
my $query = $wtk->find(
-tables => [qw(mytable1 mytable2 ...)],
-where => { name => "...", ... },
-wherelike => {...},
-group => [qw(id name ...)],
-order => [qw(id name ...)],
-limit => 10,
-distinct => 1,
);</pre>
<p>To access the records of the result set, use the normal DBI methods:</p>
<pre>
my $array = $query->fetchrow_arrayref();
my $hash = $query->fetchrow_hashref();
while (my $record = $query->fetchrow_arrayref()) {
# ...
}
# ...</pre>
<p>
</p>
<h3><a name="create__"><code>create()</code></a></h3>
<p>To insert a record, use the <code>create()</code> method:</p>
<pre>
my $id = $wtk->create(
-table => "...",
-row => { name => "...", ... },
);</pre>
<p>
</p>
<h3><a name="update__"><code>update()</code></a></h3>
<p>To update fields in a record, use the <code>update()</code> method:</p>
<pre>
my $success = $wtk->update(
-table => "...",
-set => { name => "...", ... },
-where => { ... },
-wherelike => { ... },
);</pre>
<p>
</p>
<h3><a name="remove__"><code>remove()</code></a></h3>
<p>To delete records, use the <code>remove()</code> method:</p>
<pre>
my $query = $wtk->remove(
-table => "...",
-where => { ... },
-wherelike => { ... },
);</pre>
<p>
</p>
<h3><a name="query__"><code>query()</code></a></h3>
<p>Any kind of other query can be executed using the <code>query()</code> method:</p>
<pre>
my $query = $wtk->query( $sql );</pre>
<p>
</p>
<h3><a name="load__"><code>load()</code></a></h3>
<p>This method is used to import a text file that contains a number of
records into a certain table in the database. This is nice, if you
set up many databases for an application and want to insert some
default data all at once.</p>
<p>Example:</p>
<pre>
load( 'my_project', 'default_data', 'my_table' );</pre>
<p>This example will load the file <em>data/my_project/default_data.txt</em>
from the configured <em>private</em> directory into the database
table named ``my_table'' (in the configured database).</p>
<p>The data file must be in a certain format. Here is an example:</p>
<pre>
[1]
name:Mr.X
age:23</pre>
<pre>
[2]
name:Mr.Y
age:56
bio.
Born in 1980, Mr.Y
was the first to invent
the toaster.</pre>
<pre>
[3]
name:Mrs.Y
age:25</pre>
<p>Each data file can contain zero or more records, each of which
starts with a line containing the id of the record in brackets.
Each line after that contains a field value, which starts with the
field name followed by a colon (``:''), followed by the field value
up to the end of line (without the newline).</p>
<p>If a field value contains newlines, the fieldname must be followed
by a dot (instead of a colon) and the following lines are considered
the value of the field. The field value lines must contain a
space character (space or horizontal tab) at the line start,
which identifies them as field value lines but is ignored.</p>
<p>Due to the format, certain restrictions apply to data that
is stored in data files:</p>
<ol>
<li><strong><a name="item_the_table_must_have_a_column_named_id_2e">The table must have a column named <em>id</em>.</a></strong><br />
</li>
<li><strong><a name="item_field_names_are_not_allowed_to_contain_colons_2c_d">Field names are not allowed to contain colons, dots
or newline characters.</a></strong><br />
</li>
</ol>
<p>When inserted in the database, CGI::WebToolkit checks first, if a certain row
with that id already exists. If so, nothing happens. In almost all
cases you do not want to have your data in the database be overwritten
by data from data files.</p>
<p>Empty lines in data files and space characters before the colon
are completely ignored.</p>
<p>
</p>
<h2><a name="methods_for_user_and_rights_management">Methods for user and rights management</a></h2>
<p>
</p>
<h3><a name="login__"><code>login()</code></a></h3>
<p>The <code>login()</code> method associates the current session with a user,
aka it logs the user in. The method takes two parameters,
the username and the password:</p>
<pre>
$wtk->login( $username, $password );</pre>
<p>To work, the -usertable option has to be configured (s.a.).</p>
<p>After logging in, the user's data is available in the session
under the name <em>user</em>.</p>
<p>The method returns 1 on success and 0 on failure.</p>
<p>
</p>
<h3><a name="logout__"><code>logout()</code></a></h3>
<p>This method removes any associated user from the current session,
aka logt the user out.</p>
<p>
</p>
<h3><a name="allowed__"><code>allowed()</code></a></h3>
<p>This method checks for a given workflow function name if the given
user (or the current session user) is allowed to execute the
workflow function.</p>
<p>It gets two parameter, first the workflow function name and
second optionally the user name, which defaults to the currently
logged in user, if any. If no user is logged in and no username
is given as second parameter, then the special username <em>guest</em>
is used. <code>allowed()</code> returns 1 if the user is allowed to execute the
workflow function, 0 therwise.
</p>
<p>In order to determine, if the user has access, the access configuration
file is loaded from <em>accessconfigs/</em> in the <em>private</em> directory.
This file maps workflow function names to access function names.
The appropriate access function is then executed and tells CGI::WebToolkit
if the user should be given access.
</p>
<p>The access functions are stored in <em>accesschecks/</em> in the
<em>private</em> directory and are raw subroutine bodies. When called,
the special variable $wtk is magically available, which is the
CGI::WebToolkit instance. The subroutine body should return either 1 or 0.
Additionally the workflow function name and the username
that are beeing checked are passed to the subroutine body
as first and second parameter in the array @args.
</p>
<p>Here is an example of such
an access check subroutine body that would go inside a file
in <em>accesschecks</em> in the <em>private</em> directory:
</p>
<pre>
my ($wf, $username) = @args;
if ($username eq 'root') {
return 1;
}
elsif ($wf eq 'my_project.public.home') {
return 1;
}
else {
return 0;
}
</pre>
<p>The format of an access configuration file is the same as
of a normal config file. Here is an example:
</p>
<pre>
.*: my_project.general_rights
admin\..*: my_project.admin_rights
</pre>
<p>This file says in the first line that for all workflow functions
matching ``.*'' the access check function named <em>my_project.general_rights</em>
will be consulted. For all workflow functions matching ``admin\..*''
(means literally: in the group of ``admin'') the access check function
named <em>my_project.admin_rights</em> should be consulted.
</p>
<p>If a workflow function name is matching more than one entry
in an access configuration file, <em>all</em> of the matching entries
are processed and <em>all</em> of them have to grant the user access,
to finally grant access.
</p>
<p>
</p>
<h2><a name="methods_for_internationalization">Methods for Internationalization</a></h2>
<p>
</p>
<h3><a name="___"><code>_()</code></a></h3>
<p>The <code>_()</code> (underscore-method) is used to translate a phrase into
the current or any other language. It will consult the dictionary
and return the translated string. If no translation could be found,
the phrase itself is returned.
</p>
<p>The <code>_()</code> takes two parameters: the phrase (string) and optionally
a language name, e.g. <em>en</em> or <em>en_GB</em> etc. The language names
should conform to the international naming conventions though this
is not required.
</p>
<p>Example:
</p>
<pre>
my $text_de = _('I like to walk around the block', 'de');
my $text_in_current_language =
_('Hello, World!');
</pre>
<p>
</p>
<h3><a name="lang__"><code>lang()</code></a></h3>
<p>The <code>lang()</code> method is used to set and retrieve the language
of the current session. If passed a parameter, this will be the
new current session language. The current session language is
always returned.
</p>
<p>
</p>
<h3><a name="translate__"><code>translate()</code></a></h3>
<p><code>translate()</code> is used to translate a phrase to another language.
The most common syntax is that of a sequence of pairs, with
the language identifier as the key and the phrase as value.
The first pair is used as the key phrase to be stored in the
database phrase table.
</p>
<pre>
translate( <language> => <phrase>, ... );
</pre>
<p>Example:
</p>
<pre>
translate(
'en_GB' => 'Hello!',
'de_DE' => 'Hallo!',
# you can add even more pairs
);
</pre>
<p>
</p>
<h2><a name="methods_for_form_file_upload">Methods for form file upload</a></h2>
<p>
</p>
<h3><a name="upload__"><code>upload()</code></a></h3>
<p>This method will save a file that was transferred via a normal
form submit inside a normal file form field:
</p>
<pre>
upload('attachment','my_project_uploads');
</pre>
<p>To make this example work, the form beeing submitted must
contain a file field named <em>attachment</em> and there must be
a writeable directory <em>uploads/my_project_uploads/</em> in the
<em>public</em> directory.
</p>
<p>The file is loaded from the parameter, saved inside the
directory <em>uploads/my_project_uploads/</em> in the <em>public</em> directory
and if everything goes well, a new entry like the following
is added to the session variable array named <em>uploads</em>, s.a.:
</p>
<pre>
{
'success' => 1/0,
'info' => '...',
# optional fields if upload save was successful
'path' => '...',
'filename' => '...',
'created' => '...',
'mimetype' => '',
'original_filename' => '',
}
</pre>
<p>The field <em>info</em> contains all the information from the
method CGI::uploadInfo(), including the actual filename
that was selected in the form field and the content type.
</p>
<p>To retrieve this information about the latest upload, you can
simply do the following:
</p>
<pre>
my $info = $wtk->get()->[-1];
</pre>
<p>
</p>
<h2><a name="other_methods">Other methods</a></h2>
<p>
</p>
<h3><a name="logmsg__"><code>logmsg()</code></a></h3>
<p><code>logmsg()</code> writes a text message to a logfile. It takes the message
as first parameter and optionally a priority, which can be one
of <em>DEBUG</em> (default), <em>INFO</em>, <em>WARNING</em>, <em>ERROR</em> or <em>FATAL</em>.
</p>
<p>The logfiles are kept in the private path under <em>logs</em>.
For each priority and workflow function there is a separate logfile
that can then be inspected for debugging or other reasons.
</p>
<p>
</p>
<h2><a name="predefined_template_functions">Predefined template functions</a></h2>
<p>There are a lot of predefined generator functions, which are
located in the <em>core</em> subdirectory of the <em>generators</em> directory.
</p>
<p>
</p>
<h2><a name="fileformats">Fileformats</a></h2>
<p>
</p>
<h3><a name="configuration_file_format">Configuration file format</a></h3>
<p>The configuration files have a format that allows for grouping
configuration values into separate namespaces. An example configuration
file that can be parsed is:
</p>
<pre>
# comment
name: value
name2 : value
</pre>
<p>
</p>
<h3><a name="template_file_format">Template file format</a></h3>
<p>An example template file:
</p>
<pre>
<h1>{title}</h1>
<p>{content}</p>
<i>{author:Default Value}</i>
</pre>
<p>
</p>
<hr />
<h1><a name="export">EXPORT</a></h1>
<p>None by default.
</p>
<p>
</p>
<hr />
<h1><a name="see_also">SEE ALSO</a></h1>
<p>Other modules are worth a look, including CGI, CGI::App and many more.
Use the search on cpan.org to find alternatives to the CGI::WebToolkit.
</p>
<p>There is no mailing list for this module.
</p>
<p>There is no website for this module.
</p>
<p>If you have any questions, hints or something else to say,
please mail to <a href="mailto:tokirc@gmx.net">tokirc@gmx.net</a> - thank you for helping
make CGI::WebToolkit better!
</p>
<p>
</p>
<hr />
<h1><a name="author">AUTHOR</a></h1>
<p>Tom Kirchner, <a href="mailto:tokirc@gmx.net">tokirc@gmx.net</a>
</p>
<p>
</p>
<hr />
<h1><a name="copyright_and_license">COPYRIGHT AND LICENSE</a></h1>
<p>Copyright (C) 2009 by Tom Kirchner
</p>
<p>This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.6 or,
at your option, any later version of Perl 5 you may have available.
</p>
</body>
</html>