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...

UtilPerlSkripteSubForm edit

Titel Affenformular-Demonstration
Autor AlexanderBecker
Bereich PerlSkripteCGI
Topic revision: r2 - 2009-10-03 - 18:15:53 - AlexanderBecker
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.