Affenformular-Demonstration
Affenformular
Aufgabe
Als Affenformular wird ein Programmieransatz der HTML-Formularverarbeitung von Webseiten bezeichnet. (
Quelle: Wikipedia, 27.09.2009)
Dieser Bereich zeigt ein Beispiel für ein Affenformular. CGI::Application wird als Framework zur Umsetzung der CGI-technischen Details verwendet.
Wie dem Artikel auf Wikipedia zu entnehmen ist, besteht der Programmieransatz eines Affenformulars darin, ein Formular anzuzeigen, welches, wenn es vom Benutzer abgesandt wurde, geprüft wird. Abhängig vom Ergebnis wird etwas getan. Sind die Eingaben des Nutzers korrekt, i.d.S. dass die Prüfung erfolgreich war, werden die Daten verarbeitet. Sind die Daten nicht gültig, wird wieder auf das Formular verwiesen. Sinnvollerweise - das hier gezeigte Skript macht das auch - sollten Fehlermeldungen und die bisher eingegebenen Werte im Formular angezeigt werden.
Die Umsetzung mit dem Framework CGI::Application ist (typischerweise für Perl) nur eine von vielen Möglichkeiten. Ein Affenformular kann auch, um zwei weitere Möglichkeiiten zu nennen, unter Verwendung von Catalyst oder (nur) CGI implementiert werden.
Skript
#!/Perl/bin/perl
package Affenformular;
use strict;
use warnings;
use base qw/CGI::Application/;
use CGI::Application::Plugin::Forward;
use CGI::Application::Plugin::Redirect;
use CGI::Application::Plugin::ValidateRM;
use Data::Dumper qw/Dumper/;
=head1 NAME
Affenformular
=head1 SYNOPSIS
use Affenformular;
my $app = Affenformular->new();
$app->run();
=head1 DESCRIPTION
Demo script demonstrating an Affenformular. It was inspired by the lack of such
a demo at http://de.wikipedia.org/wiki/Affenformular
=head1 METHODS
=cut
=head2 cgiapp_init()
Open database connection, setup config files, etc.
=cut
sub cgiapp_init {
my $self = shift;
# -- Set some defaults for DFV unless they already exist.
$self->param('dfv_defaults') ||
$self->param('dfv_defaults', {
missing_optional_valid => 1,
filters => 'trim',
msgs => {
any_errors => 'some_errors',
prefix => 'err_',
invalid => 'Invalid',
missing => 'Missing',
format => '<span class="dfv-errors">%s</span>',
},
});
} # /cgiapp_init
=head2 setup()
Defined runmodes, etc.
=cut
sub setup {
my $self = shift;
$self->start_mode('display_form');
$self->run_modes([qw/
display_form
validate
further_work
/]);
} # /setup
=head2 display_form( $errs? )
$errs is a (optional) hashref with errors of the validation process by
Data::FormValidator. See manpage of CGI::Application::ValidateRM for further
information.
=cut
sub display_form {
my $self = shift;
my $errs = shift; # may be undef
# Usually, we use templates, but for the sake of having this example in one
# file, we use a scalar reference as template instead of calling a template
# like this: my $t = $self->load_tmpl('my_template.tmpl');
my $form_scalar_ref = $self->_get_form();
my $t = $self->load_tmpl( \$form_scalar_ref );
$t->param($errs) if $errs; # Display errors if any. (done by the template).
# -- set some parameters, that are used in the template.
$t->param('c.query.url' => $self->query->url());
return $t->output();
} # /display_form
=head2 _get_form()
Returns a form. This is a cheap and hardly maintable way of using templates.
Note: we return a full template including html header information.
It's possible to do that in a consistent way for all runmodes using
cgiapp_postrun(). See manpage of CGI::Application for this.
=cut
sub _get_form {
my $self = shift;
my $html = q~
<html lang="en">
<head>
<title>Boring</title>
<style type="text/css" media="screen">
input.error {
border: 1pt outset #FF8000;
color: black;
background-color: #FFFFCC;
}
</style>
</head>
<body>
<h1>Affenformular</h1>
<!-- TMPL_IF CAP_Messages -->
<div style="border: 2px solid blue;">
<h2>Messages</h2>
<!-- TMPL_LOOP NAME="CAP_Messages" -->
<div class="<!-- TMPL_VAR NAME="classification" -->">
<!-- TMPL_VAR NAME="message" -->
</div>
<!-- /TMPL_LOOP -->
</div>
<!-- /TMPL_IF -->
<!-- TMPL_IF some_errors -->
<p style="color: red; font-weight: bold;">
Your input is not valid. How hard could it be? *sigh*
</p>
<!-- /TMPL_IF -->
<form action="<TMPL_VAR c.query.url>">
<input type="hidden" name="rm" value="validate" />
<fieldset>
<legend>New record of whatever</legend>
<div>
<label for"field">Random anything (e.g. "cookie", min 1, max 45
chars, required)</label>
<input type="text" name="field" id="field"
<TMPL_IF err_field>class="error"</TMPL_IF> />
</div>
<div>
<input type="submit" name="submit" value="make some" />
</div>
</fieldset>
</form>
</body>
</html>
~;
return $html;
} # /_get_form
=head2 validate()
This is where the magic happens. The user input is validated against the
profile. If valid, a results object is provided for further use.
Unless valid, the user is forwarded to display_form (given as argument to
check_rm) and errors will be provided as argument.
=cut
sub validate {
my $self = shift;
my $form_profile = {
required => [qw/field/],
optional => [qw/rm submit/],
constraints => {
field => qr/^.{1,45}$/,
}
};
# -- Validation
my $results = $self->check_rm('display_form', $form_profile) || return $self->check_rm_error_page();
# -- Further processing
# This is where you can process the user input. It is advised to use the
# results object instead the query object itself because of filters'n stuff.
# See manpage of Data::FormValidator for further information.
# -- Here you can do whatever you want to do with the user input.
# Add / delete / edit some records of a database, perform a search or do
# anything else.
# You can then display results immediately by return, e.g load a template,
# fill it with resultsets and return it's output. But you don't have to do
# all that fancy stuff in this runmode, you can forward to any runmode from
# here using forward('target_runmode').
# See manpage of CGI::Application::Forward.
# If the action should be taken only once (e.g. ehan altering a database),
# you might want to redirect the user after your work has been done. This
# way, refereshing the browser will result in calling the target runmode
# (to which the user was redirected) instead of resubmitting the form
# content for validation.
# Our "further processing" is to redirect the user to a success page.
my $url = $self->query->url() . '?rm=further_work;input=' . $results->valid('field');
return $self->redirect($url);
} # /validate
=head2 further_work()
See tailing lines of validate().
=cut
sub further_work {
my $self = shift;
my $q = $self->query();
my $output = "You successfully submited an Affenformular. You input was '"
. $q->param('input') . "'. If you did not already, you should try to "
. " submit the form without filling the required field.";
return $output;
} # /further_work
=head1 SEE ALSO
http://de.wikipedia.org/wiki/Affenformular
CGI::Application, Titanium, CGI::Application::Plugin::Forward,
CGI::Application::Plugin::Redirect, CGI::Application::Plugin::ValidateRM,
Data::FormValidator
=head1 AUTHOR
Alexander Becker E<lt>c a p f a n < a t > g m x . d eE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Alexander Becker
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.8 or, at your option,
any later version of Perl 5 you may have available.
=cut
1;
use strict;
use warnings;
my $app = Affenformular->new();
$app->run();
Ergänzungen, Kommentare
--
AlexanderBecker - 27 Sep 2009 Artikel einstellen
--
AlexanderBecker - 03 Oct 2009 Typo, Formulierungen...