PHP

PHP & OOP - Formulargenerierung und Verarbeitung (PHP Tutorial)

Tutorial erstellt von Andreas W. in PHP 5.x, letzte Änderung am 28.11.2010

In dem nachfolgenden Tutorial sollen die Grundlagen gelegt werden, die eine Implementation einer komplexen Bibliothek zur Generierung von HTML-Formularen mit Hilfe von PHP ermöglichen. Das Ziel soll es sein einen kleinen Stock an Klassen zu entwickeln, die nicht nur die Erstellung von HTML-Formularen ermöglichen, sondern zudem auch die dort eingegebenen Daten filtern, also den Ansprüchen der Applikation entsprechend anpassen, und validieren, d.h. überprüfen, können.

Dabei soll darauf geachtet werden, sowohl die einzelnen Filter, als auch Validatoren so abstrakt zu halten, dass sie zum einen leicht erweiterbar sind, und zum anderen auch vom Kontext einer Formularverarbeitung gelöst eingesetzt werden können. Zu diesem Zweck werden für die verschiedenen Klassen-Typen eigene Interfaces und abstrakte Klassen, die die Struktur der einzelnen Komponenten vorgeben, erzeugt.

Am Ende dieses Exkurses soll ein Beispiel aus der Praxis zeigen, wie eine solche Bibliothek auch in kleineren Projekten dazu eingesetzt werden kann, um ein Projekt schlanker, sicherer und anwenderfreundlicher zu gestalten. Die gezeigten Anwendungen und Methoden werden dabei ausführlich erläutert.

Motivation


Die Generierung von HTML-Formularen stellt einen Entwickler vor mehrere Probleme. Die Trennung von PHP- und HTML-Code, die Unterstützung von Mehrsprachigkeit, sowie die Trennung der Sprachdateien vom Quellcode, und abschließend die Filterung und Validierung von Daten, die über ein solches Formular eingegeben werden, gestalten sich sehr schwierig. Dies führt häufig dazu, dass PHP und HTML vermischt und die Verarbeitung der Daten in eine unendliche Verschachtelung von if und else Anweisungen ausartet.

Um dies zu verhindern, die Generierung und Verarbeitung objektorientiert zu gestalten und sowohl das Design als auch die Übersetzung vor dem Programmierer zu verbergen, sodass sich ein Designer um die gestalterischen und ein Übersetzer um die sprachlichen Aspekte kümmern kann, lohnt es sich eine Bibliothek zu programmieren, die diese Anforderungen erfüllt.

Anforderungen an eine solche Bibliothek


Um die Generierung von Formularen mit Hilfe einer in PHP entwickelten Bibliothek für einen Entwickler interessant zu machen, muss diese einer eingängigen Syntax folgen und eventuell auch in anderen Bereichen einsetzbar sein.

Zu diesem Zweck sollten Übersetzer, Filter und Validatoren einfach erweiterbar sein, einer objektorientierten Syntax folgen und unabhängig von der Formulargenerierung nutzbar sein. Um dies zu gewährleisten sollte man feste Richtlinien an diese Objekte anlegen, die zum Beispiel durch ein Inteface festgelegt werden können.

Neben der Abstrahierung von Filtern und Validatoren, ist es besonders wichtig, das Design der Formulare so zu gestalten, sodass ein Designer dieses ohne große Probleme anpassen kann. Es macht daher Sinn dem Programmierer die Möglichkeit zu geben, Formularen eindeutlige Style-Informationen zu geben, die dann durch einen Designer in einer CSS-Datei spezifiziert werden können.

Zuletzt sollten Formulare die mit dieser Bibliothek erstellt werden ohne große Probleme in mehreren Sprachen angeboten werden können. Dabei soll der Programmierer nicht mit den Übersetzungen belästigt werden. Das bedeutet, dass die Sporachdateien vom Code getrennt abgelegt werden sollen.

Filter


Die Arbeit mit Daten die durch Benutzer eingegeben werden, erfordert besondere Beachtung in Hinsicht auf Sicherheits- und Format-Aspekte.

Ein Benutzerprofil, das durch den Benutzer erstellt wird, kann zum Beispiel potentiell gefährlichen HTML-Code enthalten, der ein JavaScript Programm, das auf einem entfernten Server liegt, ausführt. Dieses Programm kann zum Beispiel Dateien auf dem aufrufenden Server löschen, verschieben oder ändern. Solche Änderungen an der Programmstruktur kann zu Sicherheitslücken und Abstürzen führen.

Ein Terminkalender, der durch die Mitglieder eines Forums gepflegt wird um beispielsweise Seminare zu koordinieren, die über Skype gehalten werden sollen, kann durch versteckte SQL-Anfragen in den Termineingaben dazu genutzt werden, Angriffe auf die dem Forum zu Grunde liegende Datenbank durchzuführen.

Abgesehen von solchen Angriffen auf eine Website bzw. einen Server können ungefilterte Daten das Layout einer Website durcheinander bringen. So können Leerzeichen, Tabs oder Zeilenumbrüche am Anfang und Ende von Datensätzen unerwünschte Absätze verursachen. Entsprechende Filter können dies verhindern.

PHP bietet bereits viele solcher Filter. So entfernt trim() nicht sichbare Zeichen am Anfang und Ende eines Strings, während strip_tags() HTML- und PHP-Code aus einer Eingabe entfernt. Leider folgen diese Filtermechanismen keiner einheitlichen Syntax, sodass sie in komplexeren Projekten nur schlecht einsetzbar sind.

Es ist also eine einheitliche, möglichst objektorientierte API von Nöten, die es ihrem Anwender erlaubt, wann immer Daten zu filtern sind, dies mit möglichst wenig neuem Code zu tun. In diesem Fall macht es Sinn ein Interface zu definieren, dass den Entwickler dazu zwingt immer die gleichen Methoden bei der Erstellung von Filtern zu implementieren, sodass man genau weiß, wie man auf diese zugreifen kann.

Code:

<?php

/**
* @package core::form
* @interface Filter
*
* The Filter interface..
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 18.02.2009
* Version 0.2, 17.11.2010 (Updated documentation.)
*/
interface Filter {
   /**
    * @public
    *
    * Executes the filter.
    *
    * @param string Value to be filtered.
    *
    * @return The filtered.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 18.02.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function filter( $value );
}

?>


Dieses Interface ermöglicht es nun dem Entwickler, einer Klasse, die zu filternde Daten zur Vefügung stellt oder entgegen nimmt, über eine zusätzliche Methode Filter der Klasse hinzuzufügen und diese dann in einer Schleife zu durchlaufen. Nachfolgend ein kleines Beispiel.

Code:

<?php

/**
* @package test
* @class FancyFilterTest
*
* The FancyFilterTest class implements a
* test of the Filter classes.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 22.11.2010
*/
class FancyFilterTest {
   /**
    * @private
    * The filter stack.
    */
   private $filters = array();

   /**
    * @private
    * Just some data.
    */
   private $data = null;

   /**
    * @private
    *
    * The default constructor assigns data
    * and filters it.
    *
    * @param string Some data.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 22.11.2010
    */
   private function __construct($dat) {
      $this->data = $dat;
      $this->filter();
   }

   /**
    * @public
    *
    * Appends a filter to the filter stack.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 22.11.2010
    */
   public function addFilter($filter) {
      // Create the hashcode, ...
      $hash = md5(serialize($filter));

      // ... check if entry exists ...
      if( !isset($this->filters[$hash]) ) {
         // ... and add filter if not.
         $this->filters[$hash] = $filter;
      }
   }

   /**
    * @public
    *
    * Executes all filters.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 22.11.2010
    */
   private function filter() {
      // Iterate over all filters ...
      foreach( $this->filters as $filter ) {
         // ... and execute them.
         $filter->filter($this->data);
      }
   }
}

?>


Eine konkrete Implementation eines Filters, der HTML- und PHP-Code aus einem Datensatz entfernt, könnte nun beispielsweise wie folgt aussehen.

Code:

<?php

/**
* @package core::form
* @class FilterStripTags
*
* The FilterStripTags class implements a filter
* that removes all code from an input value.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009
* Version 0.2, 17.11.2010 (Updated documentation.)
*/
class FilterStripTags implements Filter {
   /**
    * @public
    *
    * Removes all code from the input value.
    *
    * @param string Value to be filtered.
    *
    * @return The filtered.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 13.02.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function filter($value) {
      return strip_tags($value);
   }
}

?>


Validatoren


Abgesehen von der Filterung ist auch die Validation, die Überprüfung von Daten besonders wichtig.

Soll beispielsweise den Besuchern eines Forums eine Registrierung angeboten werden, möchte man oftmals sicherstellen, dass der Benutzername nur eine bestimmte Länge aufweist, die Email-Adresse valide ist und das Geburtsdatum einer bestimmten Formatierung folgt.

PHP bietet seit PHP 5 die sogenannten Filter-Funktionen, die solche Aufgaben übernehmen. Leider folgen auch diese keiner einheitlichen Syntax, sodass sie in komplexeren Projekten nur schlecht einsetzbar sind. Auch hier macht es deshalb Sinn eine abstrakte Klasse zu schaffen, von der alle Validatoren abgeleitet werden.

Diese abstrakte Klasse implementiert als Äquivalent zur Methode filter() eine Methode isValid(), die im Fehlerfall eine ValidatorException wirft, hinter der sich auch die Übersetzung verbirgt. Dies ist wichtig, da Validatoren anders als Filter die Daten nicht verändern, sondern nur auf ihre Korrektheit prüfen. Eine solche Klasse könnte wie folgt aussehen.

Code:

<?php

/**
* @package core::form
* @class ValidatorException
*
* The ValidatorException class implements a
* Exception type for the Validator classes.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 18.11.2010
*/
class ValidatorException extends Exception {}

/**
* @package core::form
* @class Validator
*
* The abstract Validator class
* pretends the core methods.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009
* Version 0.2, 17.11.2010 (Updated documentation.)
* Version 0.3, 18.11.2010 (Removed methods getError and setError.)
* Version 0.4, 18.11.2010 (Removed class attributes errors and messages.)
* Version 0.5, 19.11.2010 (Added default constructor and language support.)
*/
abstract class Validator {
   /**
    * @protected
    * The language object.
    */
   protected $lang = null;

   /**
    * @public
    *
    * The default constructor loads an
    * object of the Language class, which
    * offers multi language support.
    *
    * @param string Name of language file to be used.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 19.11.2010<br />
    */
   public function __construct($langFile = "Validator.Errors.Lang.ini") {
      // Check if Language object was already loaded ...
      if( $this->lang === null ) {
         // ... and get an instance of it if not.
         $this->lang = Language::getInstance();
      }
      
      // Finally add the given language file.
      $this->lang->addLanguageTags($langFile);
   }
  
   /**
    * @public
    *
    * Checks if a value is valid.
    *
    * @param string The value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   abstract public function isValid($value);
}

?>


Die Verwendung der Validatoren gestaltet sich dann ebenso wie in der oben gezeigten Test-Klasse für die konkreten Filter. Man legt sie in einer Liste ab und durchläuft sie in einer Schleife. Dabei muss man jedoch daran denken, dass die isValid()-Methode Exceptions werfen kann, wodurch es erforderlich wird die Aufrufe in einem try-catch-Block zu verpacken. Die aufgefangenen Fehler kann man dann in einem Array speichern und später geschlossen ausgeben. Das könnte dann wie folgt aussehen.

Code:

private function validate($data) {
   // Iterate over all validators ...
   foreach( $this->validators as $validator ) {
      try {
         // ... and execute them.
         $validator->isValid($data);
      }

      catch(ValidatorException $e) {
         // Handle occured errors.
         $this->errors[] = $e->getMessage();
      }
   }
}


Eine konkrete Implementation eines Validators, der eine gegebene Email-Adresse auf Korrektheit überprüft, könnte nun beispielsweise wie folgt aussehen.

Code:

<?php

/**
* @package core::form
* @class ValidatorMail
*
* The ValidatorMail class
* checks if a given input
* is valid email address.
* Code found at:
* http://iamcal.com/publish/articles/php/parsing_email
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009
* Version 0.2, 17.11.2010 (Updated documentation.)
* Version 0.3, 18.11.2010 (Removed constructor.)
* Version 0.4, 19.11.2010 (Added exception handling.)
*/
class ValidatorMail extends Validator {
   /**
    * @public
    *
    * Checks if a value is valid.
    *
    * @param string The value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    * Version 0.3, 19.11.2010 (Added exception handling.)
    */
   public function isValid($value) {
      // Declare mail pattern.
      $qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
      $dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
      $atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c';
      $atom .= '\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
      $quoted_pair = '\\x5c[\\x00-\\x7f]';
      $domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
      $quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
      $domain_ref = $atom;
      $sub_domain = "($domain_ref|$domain_literal)";
      $word = "($atom|$quoted_string)";
      $domain = "$sub_domain(\\x2e$sub_domain)*";
      $local_part = "$word(\\x2e$word)*";
      $addr_spec = "$local_part\\x40$domain";
    
      // Check if mail address is valid.
      if( !preg_match("!^$addr_spec$!", $email) ) {
         throw new ValidatorException($this->lang->get("Validator.Error.Mail"));
      }
   }
}

?>


Die hier verwendete Validierung einer Email-Adresse mit Hilfe von RegEx wurde von Cal Henderson auf seiner Website [url]http://www.iamcal.com/[/url] vorgestellt und folgt dem RFC822 Standard.

Der Übersetzer


Der in dieser Bibliothek verwendete Übersetzer wurde bereits im Tutorial PHP & OOP - Mehrsprachige Webanwendungen vorgestellt. Ein Objekt dieser Klasse wird im Konstruktor eines Validators geladen und beim Werfen einer Exception dazu verwendet die Fehlermeldung in der aktuell verwendeten Sprache auszugeben.

Ähnlich kann auch bei der Übersetzung der Formulare verfahren werden. Der Vorteil dabei ist, dass der Programmierer sich nicht um die Übersetzung kümmern muss, sondern die Sprachdateien an einen Übersetzer weitergeben kann.

Formulare mit PHP


Den Kern dieser Bibliothek bilden die Formular-Klassen. Um diese implementieren zu können, muss man sich klar machen, wie ein Formular aufgebaut ist. Es besteht aus einem Kopf-Teil, der wichtige Informationen wie zum Beispiel die verarbeitende Datei enthält, und einem Körper in dem einzelne Formular-Elemente enthalten sind. Diese Elemente bestehen wiederum aus dem eigentlichen Feld und einem Label, also einer Beschreibung.

So wie ein HTML-Formular sollten nun auch die einzelnen Klassen aufgebaut sein.

Die Form-Klasse

Man benötigt eine Form-Klasse. Diese sollte ihrerseits eine Liste an Element-Objekten verwalten und dazu benötigte Benutzer-Methoden bereitstellen. Außerdem sollte ein Name, der das Formular in der Applikation eindeutig identifiziert, ein Titel, der dem Benutzer ausgegeben wird, sowie Listen und Flags enthalten sein, die Informationen über den aktuellen Status des Formulars zur Verfügung stellen. Hinzu kommen folglich verschiedene CRUD-Methoden, sowie Methoden zum setzen und Auslesen von Daten und Fehlermeldungen, die von den einzelnen Formular-Elementen übergeben werden.

Da der Programmierer nicht mit der Ausgabe des Formulars belästigt werden soll, ist es außerdem sinnvoll, sowohl in der Form-Klasse als auch in den einzelnen Element-Klassen die __toString-Methode zu definieren, sodass das komplette Formular mit einem einfachen print-Befehl ausgegeben werden kann.

Aus diesen Informationen ergibt sich die folgende Klasse.

Code:

<?php

error_reporting(E_ALL);

/**
* @package core::form
* @class Form
*
* The Form class supports
* the handling of different forms.
* You are able to assign different elements,
* to each form.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009<br />
* Version 0.2, 17.11.2010 (Updated documentation.)
* Version 0.3, 18.11.2010 (Added language support.)
*/
class Form {
   /**
    * @private
    * The form name.
    */
   private $name = '';

   /**
    * @private
    * The form title.
    */
   private $title = '';

   /**
    * @private
    * Attributes parsed to the form.
    */
   private $attributs = array(
      'enctype' => 'application/x-www-form-urlencoded',
      'action' => '',
      'method' => 'POST'
   );
    
   /**
    * @private
    * Form elements eg. fields.
    */
   private $elements = array();
  
   /**
    * @private
    * Array that holds all errors.
    */
   private $errors = array();

   /**
    * @private
    * Flag that is set, if form was submitted.
    */
   private $hasData = false;

   /**
    * @private
    * The Language object used for translation.
    */
   private $lang = null;
  
   /**
    * @public
    *
    * The dafault constructor loads an
    * instance of the Language class to
    * offer a translation of the form name,
    * title and the names and labels of the
    * different input fields.
    *
    * @param string Name of language file to be used.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 18.11.2010
    */
   public function __construct($langFile) {
      // Check if Language object was already loaded ...
      if( $this->lang == null ) {
         // ... and get an instance of it if not.
         $this->lang = Language::getInstance();
      }
      
      // Finally add the given language file.
      $this->lang->addLanguageTags($langFile);
   }
  
   /**
    * @public
    *
    * Sets the form name.
    *
    * @param string The name to be used.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setName($name) {
      $this->name = $name;
   }

   /**
    * @public
    *
    * Sets the title for the legend field.
    *
    * @param string The title to be used.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setTitle($title) {
      $this->title = $title;
   }
  
   /**
    * @public
    *
    * Sets an attribute that should be
    * parsed to the form.
    *
    * @param string The attribute key.
    * @param string The attribute value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function addAttribute($key, $val) {      
      $this->attributs[$key] = $val;
   }

   /**
    * @public
    *
    * Adds an element to the form.
    *
    * @param FormElement The element to be added.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function addElement($element) {
      // Create the hash of the given object, ...
      $hash = md5(serialize($element));
      
      // ... check if hash already exists ...
      if( !isset($this->elements[$hash]) ) {
         // ... and add element if not.
         $this->elements[$hash] = $element;
      }
   }

   /**
    * @public
    *
    * Assigns data to the form (e.g. $_POST).
    *
    * @param Array The data to be assigned.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setData($data) {
      // Iterate over all elements of the form ...
      foreach($this->elements as $element) {
         // ... and check if data for the current element is given.
         if( array_key_exists($element->getName(), $data) && !empty($data[$element->getName()]) ) {
            // If some data is given ...
            $value = $data[$element->getName()];
        
            // ... assign it and set the input flag.
            $element->setValue($value);
            $element->hasInput();
            $this->hasData = true;
         }
        
         // If no data was given, check if data is required.
         elseif( $element->isRequired() ) {
            $element->setValue(null);
            $element->hasInput();
         }
        
         else {
            $element->flush();
         }
      }
   }

   /**
    * @public
    *
    * Returns the data set in the form.
    *
    * @return The form data.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getData() {
      // Initialize the data array, ...
      $data = array();
  
      // ... iterate over all elements of the form ...
      foreach( $this->elements as $element ) {
         // ... and get the values of them.
         $data[$element->getName()] = $element->getValue();
      }
      
      return $data;
   }
  
   /**
    * @public
    *
    * Removes all data from the form.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function flush(){
      // Iterate over all elements of the form ...
      foreach( $this->elements as $element ) {
         // ... and flush each element.
         $element->flush();
      }
      
      // Finally set the hasData flag to false.
      $this->hasData = false;
   }

   /**
    * @public
    *
    * Executes all filters.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   private function filter() {
      // Iterate over all elements of this form ...
      foreach( $this->elements as $element ) {        
         // ... and execute their registered filters.
         $element->filter();
      }
   }

   /**
    * @public
    *
    * Executes all filters.
    *
    * @return Returns true if form is valid.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function isValid() {      
      // Check if any data was given.
      if( $this->hasData == false ) {
         return false;
      }
      
      // If data is given set flag.
      $isValid = true;
      
      // Iterate over all elements of this form, ...
      foreach($this->elements as $element) {
         // ... check if they are valid ...
         if( $element->isValid() == false ) {
            // set return parameter
            $isValid = false;
            
            // get error messages
            $this->errors[$element->getName()] = $element->getErrors();
         }
      }
      
      return $isValid;
   }

   /**
    * @public
    *
    * Returns all occured errors.
    *
    * @return The occured errors.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getErrors() {
      return $this->errors;
   }
  
   /**
    * @public
    *
    * Returns the html representation of this form.
    *
    * @return The html representation.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    * Version 0.3, 18.11.2010 (Added language support)
    */
   public function __toString() {  
      // Initialize html code variable.
      $html = "\n\n<!-- start PHP created form -->\n";
      
      // Now start the form, ...
      $html .= "<form name=\""
         . $this->lang->get($this->name)
         . "\" id=\""
         . $this->lang->get($this->name)
         . "\"";
      
      // ... add the attributes ...
      foreach($this->attributs as $key => $val) {
         $html .= ' ' . $key . '="' . $val . '"';
      }
      
      $html .= ">\n";
      
      // ... and start the fieldset.
      if( !empty($this->title) ) {
         $html .= "<fieldset>\n<legend>"
            . $this->lang->get($this->title)
            . "</legend>\n";
      }
      
      // Then loop over all elements of this form, ...
      foreach($this->elements as $element) {        
         // ... add them ...
         $html .= sprintf("%s", $element);
      }
      
      // ... and end the fieldset.
      if( !empty($this->title) ) {
         $html .= "\n</fieldset>";
      }
      
      // Finally end the form ...
      $html .= "\n</form>\n";
      
      // ... and add a comment.
      $html .= "<!-- end PHP created form -->\n\n";
      
      return $html;
   }
}

?>


Die Ausgabe des Formulars soll natürlich auch abhängig von der eingestellten Sprache angepasst werden. Daher muss man auch hier auf die richtige Verwendung der Language-Klasse achten. Dabei muss man sich klar machen, welche Attribute bei der Ausgabe überhaupt übersetzt werden dürfen. Den Namen des Formulars darf man auf keinen Fall übersetzen, da das Formular sonst unter Umständen nicht mehr eindeutig identifizierbar ist.

Die Formular-Elemente


Da nun der Körper eines Formulars erzeugt werden kann, geht es nun darum  Elemente zu schaffen, die man diesem hinzufügen kann. Es gibt auch in diesem Fall verschiedene Elemente, die bei der Ausgabe, welche bereits in der __toString-Funktion der Form-Klasse implementiert wurde, in einer Schleife durchlaufen werden. Daher sollte auch hier eine abstrakte Klasse implementiert werden, von der die konkreten Element-Klassen abgeleitet werden.

Um diese implementieren zu können, müssen wir uns, wie schon bei der Implementierung der Form-Klasse klar machen, welche Funktionalität man im Regelfall erwarten würde.

Ein Formular-Element erhält einen eindeutigen Bezeichner, über den wir später die Daten aus dem $_POST-Array extrahieren können. Außerdem benötigt es ein Label (Beschriftung) und einen Wert, der entweder beim Absenden gesetzt oder vom Benutzer vorgegeben werden kann. Zudem muss es möglich sein, ein Feld als Pflichtfeld zu deklarieren, ihm Validatoren und Filter hinzuzufügen, Attribute, wie eine Stylesheet-Klasse, zuzuweisen und die Sprache des Labels je nach Einstellung anzupassen.

Es werden folglich die Klassen-Attribute und dazugehörigen CRUD-Methoden für den Bezeichner, das Label, den Wert, die Attribute und das Pflichtfeld-Flag benötigt. Sowohl Filter als auch Validatoren können wie im oben angeführten Beispiel eingebunden werden.

Besonders wichtig ist auch hier die Implementierung der __toString-Methode, die beim Aufruf der __toString-Methode der Form-Klasse ausgeführt wird. Dabei muss man darauf achten, dass auch hier wirklich nur die Attribute übersetzt werden, bei denen es Sinn macht. Einen Wert oder einen Bezeichner zu übersetzen macht keinen Sinn.

Zuletzt ist es wesentlich bei der Ausführung der Validatoren, die geworfenen Fehler abzufangen und in ein Array zu speichern. Andernfalls kann der Benutzer beim Ausfüllen des Formulars immer nur einen Fehler beheben und muss dann das Formular erneut abschicken. Nachfolgend ein kleines Codebeispiel.

Code:

public function isValid() {
   foreach(validators as $validator ) {
      try {
         $validator->isValid();
      }

      catch(ValidatorException $e) {
         $errors[] = $e->getMessage();
      }
   }
}


Die Implementation der FormElement-Klasse könnte also wie folgt aussehen.

Code:

<?php

/**
* @package core::form
* @class FormElement
*
* The Form_Element class supports
* the handling of different input fields.
* You are able to assign validators,
* names and values to each input element.
* Finally you are able to assign
* diferent filters to each input field.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009<br />
* Version 0.2, 17.11.2010 (Updated documentation.)
* Version 0.3, 19.11.2010 (Updated error handling.)
*/
abstract class FormElement {
   /**
    * @protected
    * The element name.
    */
   protected $name = null;
  
   /**
    * @protected
    * The element value.
    */
   protected $value = null;
  
   /**
    * @protected
    * The element label.
    */
   protected $label = null;
  
   /**
    * @protected
    * The required flag.
    */
   protected $required = false;
  
   /**
    * @protected
    * The attribute array.
    */
   protected $attributs = array();
  
   /**
    * @protected
    * The validator array.
    */
   protected $validators = array();
  
   /**
    * @protected
    * The filter array.
    */
   protected $filters = array();
  
   /**
    * @protected
    * The error array.
    */
   protected $errors = array();
  
   /**
    * @protected
    * The hasInput flag.
    */
   protected $hasInput = false;
  
   /**
    * @protected
    * The Language object used for translation.
    */
   protected $lang = null;

   /**
    * @public
    *
    * Default constructor is called when
    * the class is instanced.
    *
    * @param string The name to be used.
    * @param string The required flag.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function __construct($name, $required = false) {
      // Set class attributes.
      $this->name = $name;
      $this->required = $required;
      
      // If element is required add NotEmpty validator.
      if( $this->required == true ) {
         $this->addValidator( new ValidatorNotEmpty() );
      }
      
      // Get an instance of it if not.
      $this->lang = Language::getInstance();
   }

   /**
    * @public
    *
    * Assigns a value to an element.
    *
    * @param string The value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setValue($value) {
      $this->value = $value;
   }
  
   /**
    * @public
    *
    * Clears the value of the form element.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function flush() {
      // Check if element is an instance of FormElementSubmit or FormElementReset ...
      if( !($this instanceof FormElementSubmit) && !($this instanceof FormElementReset) ) {
         // ... and set the value to null if not.
         $this->value = null;
      }
      
      // Finally reset the hasInput flag.
      $this->hasInput = false;
   }
  
   /**
    * @public
    *
    * Returns true if element must be filled.
    *
    * @return Returns true if element must be filled.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function isRequired() {
      return ($this->required == true) ? true : false;
   }

   /**
    * @public
    *
    * Assigns a label to the element.
    *
    * @param string The label.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setLabel($label) {
      $this->label = $label;
   }
  
   /**
    * @public
    *
    * Adds a validator to the element.
    *
    * @param Validator The validator to be added.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function addValidator($validator) {
      // Create a hash of the validator object, ...
      $hash = md5(serialize($validator));
      
      // ... check if this hash already exists ...
      if( !isset($this->validators[$hash]) ) {
         // ... and append validator to list if not.
         $this->validators[$hash] = $validator;
      }
   }
  
   /**
    * @public
    *
    * Adds a filter to the element.
    *
    * @param Filter The filter to be added.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function addFilter($filter) {
      // Create a hash of the filter object, ...
      $hash = md5(serialize($filter));
      
      // ... check if this hash already exists ...
      if( !isset($this->filters[$hash]) ) {
         // ... and append filter to list if not.
         $this->filters[$hash] = $filter;
      }
   }
  
   /**
    * @public
    *
    * Adds an attribute to the element.
    *
    * @param string The attribute key.
    * @param mixed The attribute value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function addAttribute($key, $val) {      
      // Check if attribute was already set ...
      if( !isset($this->attributs[$key]) ) {
         // ... and append attribute to list if not.
         $this->attributs[$key] = $val;
      }
   }
  
   /**
    * @public
    *
    * Returns the name of this element.
    *
    * @return The elements' name.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getName() {
      return $this->name;
   }

   /**
    * @public
    *
    * Returns the value of this element.
    *
    * @return The elements' value.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getValue() {
      return $this->value;
   }

   /**
    * @public
    *
    * Returns the label of this element.
    *
    * @return The elements' label.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getLabel() {
      return $this->label;
   }
  
   /**
    * @public
    *
    * Executes all filters of this element.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function filter() {
      // Iterate over all filters assigned to this element ...
      foreach( $this->filters as $filter ) {
         // ... and execute the different filters.
         $this->value = $filter->filter( $this->value );
      }
   }
  
   /**
    * @public
    *
    * Executes all validators of this element.
    *
    * @return Returns true if all validators success.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function isValid() {
      // Initialize the return parameter.
      $isValid = true;
      
      // Execute all filters.
      $this->filter();
      
      // Check if there was an input ...
      if( $this->hasInput === false ) {
         // ... and return true if not.
         return true;
      }
      
      // If there is some input, check if this element is required.
      else if( ($this->required === true) || !empty($this->value) ) {        
         // Execute all validators assigned to this element.
         foreach( $this->validators as $validator ) {
            // If the value is an array, ...
            if( is_array($this->value) ) {
               // ... loop over its values ...
               foreach( $this->value as $value ) {
                  // ... and check if they are valid.                  
                  try {
                     $validator->isValid($this->value);
                  }
        
                  catch(ValidatorException $e) {
                     // If an exception occured append it to the error list ...
                     $this->addErrors($e->getMessage());
                     // ... and set the isValid flag.
                     $isValid = false;
                  }
               }
            }

            // If it is a single value, ...
            else {
               // ... check if it is valid.                  
               try {
                  $validator->isValid($this->value);
               }
      
               catch(Exception $e) {
                  // If an exception occured append it to the error list ...
                  $this->addErrors($e->getMessage());
                  // ... and set the isValid flag.
                  $isValid = false;
               }
            }
         }
      
         return $isValid;
      }
      
      // Otherwise return true.
      else {
         return true;
      }
   }
  
   /**
    * @public
    *
    * Set the hasInput flag.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function hasInput() {
      $this->hasInput = true;
   }

   /**
    * @public
    *
    * Appends an array of errors to the error list.
    *
    * @param array The errors to be append.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    * Version 0.3, 19.11.2010 (Updated error handling.)
    */
   private function addErrors($errors) {
      // If an array is given ...  
      if( is_array($errors) ) {
         // ... loop over the given array, ...
         foreach($errors as $error) {
            // ... create a hash for each entry, ...
            $hash = md5($error);
  
            // ... check if error is already set ...
            if( !isset($this->errors[$hash]) ) {
               // ... and append it if not.
               $this->errors[$hash] = $error;
            }
         }
      }

      // Otherwise ...
      else {
         // ... create a hash for each entry, ...
         $hash = md5($errors);
  
         // ... check if error is already set ...
         if( !isset($this->errors[$hash]) ) {
            // ... and append it if not.
            $this->errors[$hash] = $errors;
         }
      }
   }

   /**
    * @public
    *
    * Returns the error list.
    *
    * @return The error list.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function getErrors() {
      return $this->errors;
   }
}

?>


Die wohl wichtigste Element-Klasse ist der Sende-Button. Daher nachfolgend eine beispielhafte Implementierung.

Code:

<?php

/**
* @package core::form
* @class FormElementSubmit
*
* The FormElementSubmit class
* represents a submit field.
* You are able to assign a name, a value
* and a label.
*
* @author Andreas Wilhelm
* @version
* Version 0.1, 13.02.2009
* Version 0.2, 17.11.2010 (Updated documentation.)
* Version 0.3, 18.11.2010 (Added language support)
*/
class FormElementSubmit extends FormElement {
   /**
    * @public
    *
    * Overwrites the isRequired method.
    *
    * @return Always true.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function isRequired() {
      return false;
   }
  
   /**
    * @public
    *
    * Overwrites the isValid method.
    *
    * @return Always true.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function isValid() {
      return true;
   }
  
   /**
    * @public
    *
    * Overwrites the setValue method.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    */
   public function setValue() {}


   /**
    * @public
    *
    * Returns the html representation of this element.
    *
    * @return The html representation.
    *
    * @author Andreas Wilhelm
    * @version
    * Version 0.1, 30.08.2009
    * Version 0.2, 17.11.2010 (Updated documentation.)
    * Version 0.3, 18.11.2010 (Added language support)
    */
   public function __toString() {
      // Initialize the html code variable and add the name.
      $html = '<input type="submit" name="' . $this->name . '"';
      
      // Now add the value, ...
      $html .= ' value="' . $this->lang->get($this->label) . '"';
      
      // ... add the attributes ...
      foreach($this->attributs as $key => $val) {
         $html .= ' ' . $key . '="' . $val . '"';
      }
      
      // ... and finally close the tag.
      $html .= " />";
      
      return $html;
   }
}

?>


Ein Beispiel aus der Praxis


Zum Abschluss soll nun ein Feedback-Formular mit der neu implementierten Bibliothek erstellt werden. Dies ist ein typisches Beispiel aus der Praxis, welches gerade bei kleineren Projekten oft anzutreffen ist.

Als erstes erstellt man nun das Formular mit Hilfe der neuen Bibliothek. Dies könnte dann wie folgt aussehen.

Code:

<?php

// Set error_reporting flag.
error_reporting(E_ALL);

// Load the required classes.
require_once('./lang/Language.php');
require_once('./form/Form.php');
require_once('./form/FormElement.php');
require_once('./form/FormElementRadio.php');
require_once('./form/FormElementTextarea.php');
require_once('./form/FormElementSubmit.php');
require_once('./form/FormElementReset.php');
require_once('./form/Validator.php');
require_once('./form/ValidatorNotEmpty.php');
require_once('./form/ValidatorLength.php');
require_once('./form/Filter.php');
require_once('./form/FilterTrim.php');
require_once('./form/FilterStripTags.php');

try {
   // Get an instance of the Language class, ...
   $lang = Language::getInstance();
  
   // ... set the default language ...
   $lang->setDefault('de');
  
   // ... and set current language.
   if( isset($_GET['lang']) ) {
      // Finally set a new current language ...
      $lang->setLanguage($_GET['lang']);
      
      // ... and dump the language name.
      if( $_GET['lang'] == "en" ) {
         echo "Language: English\n";
      }
      
      else if( $_GET['lang'] == "de" ) {
         echo "Sprache: Deutsch\n";
      }
      
      else {
         echo "Using default Language!\n";
      }
   }
  
   /* create the form */
   $form = new Form('Form.Feedback.ini');
   $form->setName('feedback_form');

   /* creating Form Elements */
   $from = new FormElementRadio('from', true);
   $from->setLabel('Form.Feedback.From');
   $from->addOption("Form.Feedback.Option.SearchEngine");
   $from->addOption("Form.Feedback.Option.Known");
   $from->addOption("Form.Feedback.Option.Press");
   $from->addOption("Form.Feedback.Option.Link");
   $from->addOption("Form.Feedback.Option.Other");
   $from->addFilter( new FilterTrim() );
   $from->addFilter( new FilterStripTags() );
  
   $cause = new FormElementTextarea('cause', true);
   $cause->setLabel("Form.Feedback.Cause");
   $cause->addAttribute('style', 'width: 400px; height: 100px;');
   $cause->addFilter( new FilterTrim() );
   $cause->addFilter( new FilterStripTags() );
   $cause->addValidator( new ValidatorLength(20, 500) );
  
   $found = new FormElementRadio('found', true);
   $found->setLabel("Form.Feedback.Found");
   $found->setValue('ja');
   $found->addOption("Form.Feedback.Option.Yes");
   $found->addOption("Form.Feedback.Option.No");
   $found->addFilter( new FilterTrim() );
   $found->addFilter( new FilterStripTags() );
  
   $evaluation = new FormElementRadio('evaluation', true);
   $evaluation->setLabel('Form.Feedback.Evaluation');
   $evaluation->addOption('Form.Feedback.Option.Brilliant');
   $evaluation->addOption('Form.Feedback.Option.Good');
   $evaluation->addOption('Form.Feedback.Option.Ok');
   $evaluation->addOption('Form.Feedback.Option.Bad');
   $evaluation->addFilter( new FilterTrim() );
   $evaluation->addFilter( new FilterStripTags() );
  
   $infos = new FormElementRadio('infos', true);
   $infos->setLabel('Form.Feedback.Infos');
   $infos->addOption('Form.Feedback.Option.Brilliant');
   $infos->addOption('Form.Feedback.Option.Good');
   $infos->addOption('Form.Feedback.Option.Ok');
   $infos->addOption('Form.Feedback.Option.Bad');
   $infos->addFilter( new FilterTrim() );
   $infos->addFilter( new FilterStripTags() );
  
   $order = new FormElementRadio('order');
   $order->setLabel('Form.Feedback.Order');
   $order->addOption('Form.Feedback.Option.Brilliant');
   $order->addOption('Form.Feedback.Option.Good');
   $order->addOption('Form.Feedback.Option.Ok');
   $order->addOption('Form.Feedback.Option.Bad');
   $order->addFilter( new FilterTrim() );
   $order->addFilter( new FilterStripTags() );

   $message = new FormElementTextarea('message');
   $message->setLabel('Form.Feedback.Message');
   $message->addAttribute('style', 'width: 400px; height: 150px;');
   $message->addFilter( new FilterTrim() );
   $message->addFilter( new FilterStripTags() );
   $message->addValidator( new ValidatorLength(20, 1500) );

   $submit = new FormElementSubmit('submit');
   $submit->setLabel('Form.Feedback.Submit');

   $reset = new FormElementReset('reset');
   $reset->setLabel('Form.Feedback.Reset');

   // Add all elements to the form.
   $form->addElement($from);
   $form->addElement($cause);
   $form->addElement($found);
   $form->addElement($evaluation);
   $form->addElement($infos);
   $form->addElement($order);
   $form->addElement($message);
   $form->addElement($submit);
   $form->addElement($reset);
  
   // Check if some data was submitted ...
   if( !empty($_POST) ) {
      // ... and set form data if so.
      $form->setData($_POST);
   }
      
   echo $form;
}

catch(Exception $e) {
   echo $e->getMessage();
}

?>


Anschließend erstellen wir die benötigten Sprachdateien, die eine Darstellung des Forumlars unter Verwendung verschiedener Sprachen und die mehrsprachige Ausgabe von Fehlermeldungen der Validatoren ermöglichen.

Form.Feedback.ini
Code:

[en]
Form.Feedback.From = "How did you hear about our website? *"
Form.Feedback.Cause = "What was your intention in visiting our website? *"
Form.Feedback.Found = "Did you finde what you was interessted in? *"
Form.Feedback.Evaluation = "Did you like our website? *"
Form.Feedback.Infos = "Do you like the amount of informations on our website? *"
Form.Feedback.Order = "How would you juge the order-flow"
Form.Feedback.Message = "Criticism / praise / suggestions"
Form.Feedback.Submit = "Send feedback"
Form.Feedback.Reset = "Reset formular"

Form.Feedback.Option.SearchEngine = "SearchEngine"
Form.Feedback.Option.Known = "Common People/Friends"
Form.Feedback.Option.Press = "Press"
Form.Feedback.Option.Link = "Link from another website"
Form.Feedback.Option.Other = "Other"
Form.Feedback.Option.Yes = "yes"
Form.Feedback.Option.No = "no"

Form.Feedback.Option.Brilliant = "Brilliant"
Form.Feedback.Option.Good = "Good"
Form.Feedback.Option.Ok = "Ok"
Form.Feedback.Option.Bad = "Bad"

[de]
Form.Feedback.From = "Wie haben Sie von unserer Internetpräsenz erfahren? *"
Form.Feedback.Cause = "Aus welchem Grund besuchen Sie diese Website? *"
Form.Feedback.Found = "Haben Sie die gesuchten bzw. interessante Informationen gefunden? *"
Form.Feedback.Evaluation = "Wie hat ihnen unsere Internetpräsenz gefallen? *"
Form.Feedback.Infos = "Wie beurteilen Sie die von uns zur Verfügung gestellten Informationen? *"
Form.Feedback.Order = "Wie würden Sie den Bestell-Ablauf beurteilen?"
Form.Feedback.Message = "Kritik/Lob/Anregungen"
Form.Feedback.Submit = "Feedback Absenden"
Form.Feedback.Reset = "Formular Zurücksetzen"

Form.Feedback.Option.SearchEngine = "Suchmaschiene"
Form.Feedback.Option.Known = "Bekannte/Freunde"
Form.Feedback.Option.Press = "Presse"
Form.Feedback.Option.Link = "Link von einer anderen Website"
Form.Feedback.Option.Other = "Andere"
Form.Feedback.Option.Yes = "ja"
Form.Feedback.Option.No = "nein"

Form.Feedback.Option.Brilliant = "Brilliant"
Form.Feedback.Option.Good = "Gut"
Form.Feedback.Option.Ok = "Ok"
Form.Feedback.Option.Bad = "Schlecht"


Validator.Errors.Lang.ini
Code:

[en]
Validator.Error.Alnum = "Alphanumeric input required."
Validator.Error.Alpha = "Alphabetic input required."
Validator.Error.Between = "Numerical input between %d and %d required."
Validator.Error.Date = "Valid date required."
Validator.Error.Float = "Floating point input required."
Validator.Error.Greater = "Numerical input greater than %d required."
Validator.Error.Hex = "Hexadecimal input required."
Validator.Error.Integer = "Integer input required."
Validator.Error.Length.Minimum = "Input should have a length greater than %d."
Validator.Error.Length.Maximum = "Input should have a length smaller than %d."
Validator.Error.Lower = "Numerical input lower than %d required."
Validator.Error.Mail = "Valid email address required."
Validator.Error.NotEmpty = "Any input required."
Validator.Error.Phone = "Valid phone number required."
Validator.Error.Regex = "Input does not match requirements."
Validator.Error.Url = "Valid url required."

[de]
Validator.Error.Alnum = "Es ist eine alphanumerische Eingabe erforderlich."
Validator.Error.Alpha = "Es ist eine alphabetische Eingabe erforderlich."
Validator.Error.Between = "Numerische Eingabe zwischen %d und %d erforderlich."
Validator.Error.Date = "Valide Dateumsangabe erforderlich."
Validator.Error.Float = "Floatingpoint Eingabe erforderlich."
Validator.Error.Greater = "Numerische Eingabe größer %d erforderlich."
Validator.Error.Hex = "Hexadezimale Eingabe erforderlich."
Validator.Error.Integer = "Ganzzahlige Eingabe erforderlich."
Validator.Error.Length.Minimum = "Eingabe der Länge größer %d erforderlich."
Validator.Error.Length.Maximum = "Eingabe der Länge kleiner %d erforderlich."
Validator.Error.Lower = "Numerische Eingabe kleiner %d erforderlich."
Validator.Error.Mail = "Valide Email Adresse erforderlich."
Validator.Error.NotEmpty = "Eingabe darf nicht leer sein."
Validator.Error.Phone = "Valide Telefon Nummer erforderlich."
Validator.Error.Regex = "Eingabe muss den Anforderungen entsprechen."
Validator.Error.Url = "Valide URL erforderlich."


Wenn man möchte, kann man nun noch die Formatierungen des Formulars über ein Stylesheet vornehmen. In diesem Beispiel wurde die im Anhang enthaltene CSS-Datei verwendet.

Lässt man den Test nun laufen, sollte man am Anfang der Seite die aktuell verwendete Sprache sehen und danach sollte das Feedback-Formular ausgegeben werden. Treten nach dem Absenden Fehlermeldungen auf, sollten diese in rot zwischen dem Label und dem dazugehörigen Eingabefeld ausgegeben werden.

Die fertige Bibliothek


Eine bereits implementierte Bibliothek gibt es natürlich auch. Diese findet ihr als *.zip-Archiv im Bereich Skripte des Download-Archivs. Ich möchte darum bitten, an diesen Klassen nur unter Rücksprache etwas zu ändern und die eingefügten Kommentare und Versions-Hinweise nicht zu entfernen.

Hinweise zur Implementation, Erweiterungsvorschläge oder BugFixes sind natürlich gern gesehen und können, wie unter Fragen & Antworten beschrieben, an mich weitergegeben werden.

Fragen und Antworten


Fragen und Antworten findet ihr selbstverständlich bei uns im Forum. Ich möchte euch auch darum bitten, keine Fragen an mich persönlich zu senden aus dem einfachen Grund, dass die anderen Leser in diesem Fall nichts von den gegebenen Antworten haben. Zudem können euch im Forum auch viele andere Benutzer, die viel Ahnung haben, helfen. Natürlich freue ich mich über ein kurzes Feedback zu diesem Tutorial. Auch ein Link oder Blog-Post kann helfen. Ich bedanke mich für eure Aufmerksamkeit und hoffe, dass euch mein kurzer Exkurs gefallen hat.

Liebe Grüße,

Andreas

http://www.avedo.net

Dieses Tutorial zeigt eine mögliche Implementation einer Bibliothek zur Generierung und Verarbeitung von Formularen.


>> Allgemeine Fragen oder Probleme mit dem Tutorial? Hier gehts zum Forum!

Impressum / Datenschutzerklärung          © der-Webdesigner.net 2002 - 2011           top ▲