Kontaktformular-Tutorial

Diese Seite beinhaltet veraltete Komponenten, die nicht mehr im Release 1.11 enthalten sind. Die Seite befindet sich deshalb bis zum Entfernen dieser Meldung in einem Bearbeitungszustand. Sollten Fragen auftauchen, können diese gerne im Forum gestellt werden.

Die aktuelle Art der Einbindung des Kontakt-Formulars ist in einem copy&paste-Tutorial im Wiki beschrieben.

1. Einleitung

Das vorliegende Tutorial möchte eine weitere Anwendung der Formular-TagLibs und des <core:importdesign />-Tags zeigen. Das hier diskutierte Kontakt-Formular bietet die Möglichkeit, Empänger-Adressen vor Grabbern und Bots zu schützen, die E-Mail-Adressen von Webseiten auslesen. Die Empfängerliste des Formulars ist beliebig konfigurier- und erweiterbar. Die Anwendung kann mit Hilfe des <core:importdesign />-Tags an beliebiger Stelle in eine Page-Controller-basierte Anwendung eingebunden werden.
Im Release 1.11 wurde das HTML-Markup des Moduls vollständig überarbeitet. Aus diesem Grund muss bei der Einbindung des Moduls die beiliegende CSS-Datei (siehe /modules/kontakt4/pres/css/contact.css im Release-Package) in den Header der betreffenden Seite eingebunden werden. Diese beinhaltet bereits einen Basis-Satz an CSS-Definitionen und muss an den jeweiligen Stil der Seite angepasst werden. Eine genaue Beschreibung kann dem Wiki unter Kontakt-Formular-Modul entnommen werden.

2. Grundlagen

Auch in diesem Tutorial werden Techniken eingesetzt, die bereits in den vorangegangenen Tutorials zur Anwendung gekommen sind. Der Autor geht davon aus, dass das Kapitel 2 des Kommentarfunktion-Tutorials gelesen und verstanden wurden. Kapitel 2 beschreibt dabei die Trennung der Funktionen einer Software in drei Schichten, denen unterschiedliche Funktionen zugeteilt werden. Weiterhin beschreibt das Kapitel, wie Domain-Objekte zur Kommunikation zwischen den genannten Schichten fungieren und welche Rolle das MVC-Pattern bei der Implementierung einer Anwendung spielt.


2.1. Konfiguration

Um die Applikation in unterschiedlichen Projekten einsetzbar zu machen müssen Projekt-spezifische Belange in Konfigurationsdateien ausgelagert werden. Konfiguration ist beim Kontaktformular in zweierlei Hinsicht notwendig: Zum einen müssen die Enpfänger-Namen und -Adressen konfigurierbar sein, zum anderen müssen die Ausgabetexte der verwendeten Formular-TagLibs (Validatoren) für das Projekt konfiguriert werden.

An dieser Stelle soll ein kleiner Exkurs zur Konfiguration der Formular-Validatoren eingeschoben werden:
Die Tags
  • <form:validate />
  • <valgroup:validate />
benötigen zur Ausgabe einer Validierungsmeldung eine sprachabhängige Konfigurationsdatei, die die entsprechenden Texte beinhaltet. Die Konfigurationsdatei wird dabei unter dem Pfad
Code
/config/tools/form/taglib/{CONTEXT}/{ENVIRONMENT}_formconfig.ini
erwartet. {CONTEXT} ist dabei der Context der aktuellen Applikation und {ENVIRONMENT} ist gegen den Wert der Umgebungsvariable der Registry zu ersetzen. Im Fall der vorliegenden Dokumentationsseite wird die Datei unter
Code
/config/tools/form/taglib/sites/demosite/DEFAULT_formconfig.ini
erwartet. Wie im Kapitel Standard TagLibs unter 2.3.16 und 2.3.17 zu lesen ist, können jedem der genannten Tags die optionalen Attribute
  • msginputreq=""
  • msginputwrg=""
mitgegeben werden. Diese definieren einen Konfigurationsschlüssel, der einen sprachabhängigen Text enthällt, der bei Eingabe eines nicht gültigen Wertes angezeigt wird. Mit diesem Mechanismus werden zwei Bereiche abgedeckt: einerseits ist es möglich, einen Satz an Texten für eine komplette Applikation zu definieren und diese anschließend in mehreren Modulen nutzen zu können, zum anderen werden die Texte in einfache Textedateien ausgelagert und können einfach übersetzt werden.

Beispiel:
Soll bei der Validierung eines E-Mail-Feldes der Text
APF-Template
Bitte geben Sie eine E-Mail-Adresse sein!
erscheinen, wenn das Feld nicht gefüllt wurde und
APF-Template
Bitte geben Sie eine gültige E-Mail-Adresse sein!
wenn das Feld nicht mit einer syntaktisch richtigen E-Mail-Adresse gefüllt wurde, dann kann für dieses Feld innerhalb eines Formulars wie folgt ein Validator-Tag definiert werden:
APF-Template
<form:validate button="send" field="email" type="EMail" msginputreq="Contact.EMail.InputRequired" msginputwrg="Contact.EMail.InputWrong" />
Das Attribut button definiert dabei den Namen des Button, der die Validierung auslösen soll, das Attribut field das zu validierende Feld und type den Validator-Typ. Die Inhalte der Attribute msginputreq und msginputwrg wurden in diesem Fall mit dem Prefix "Contact.EMail." versehen um die Zugehörigkeit zur Applikation Kontaktformular und zum Feld E-Mail kenntlich zu machen. Diese Konvention hat sich eingebürgert, um schnell erkennen zu können, welcher Konfigurationsschlüssel zu welcher Applikation gehört. Des Weiteren ist es ratsam, die Konfigurationsdateien zu kommentieren.

Die Konfigurationsdatei muss damit bei Betrieb der Applikation in deutscher und englischer Sprache folgenden Inhalt haben:
APF-Konfiguration
[de] Contact.EMail.InputRequired = "Bitte geben Sie eine E-Mail-Adresse sein!" Contact.EMail.InputWrong = "Bitte geben Sie eine gültige E-Mail-Adresse sein!" [en] Contact.EMail.InputRequired = "Please fill the field sender name!" Contact.EMail.InputWrong = "Please provide a valid email address!"

2.2. Mehrsprachigkeit

Das Framework bietet mehrere Möglichkeiten Applikationen und Module auf Mehrsprachigkeit auszulegen. Zum einen wird die Sprache eines Objekts in jedem DOM-Knoten mitgeführt und der Entwickler hat damit die Möglichkeit sprachabhängige Texte in einem Document-Controller einzusetzen, zum anderen gibt es XML-Tags wie
  • <html:getstring />
  • <template:getstring />
  • <form:getstring />
die sprachabhängige Texte aus Konfigurationsdateien an enstprechenden Stellen anzeigen. Im Fall des Kontaktformulars wird eine Mischform eingesetzt. Als Basis für beide Möglichkeiten dient eine gemeinsame Konfigurationsdatei
APF-Template
/config/modules/kontakt4/{CONTEXT}/{ENVIRONMENT}_language.ini
Diese wird mit folgenden Werten gefüllt:
APF-Konfiguration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Deutsche Texte ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [de] ; Header header.title = "Kontakt" ; Hinweise zum Formular formhint.text = "Wenn Sie mit mir in Kontakt treten möchten, dann benutzen Sie einfach dieses Formular. Geben Sie Ihre Nachricht ein und schon kann es los gehen. Ich werden mich dann umgehend mit Ihnen in Verbindung setzten. Bitte füllen Sie das Formular vollständig aus!" ; Formular form.person = "Person / Gruppe: " form.name = "Ihr Name:" form.email = "Ihre E-Mail-Adresse:" form.subject = "Ihr Betreff:" form.comment = "Ihre Nachricht:" form.button = "Senden" form.captcha = "Bestätigungscode:" ; confirmation text message.text = "Vielen Danke für Ihre Anfrage. Ich werde mich umgehend mit Ihnen in Verbindung setzen!" ; validation messages form.name.error = "Bitte füllen Sie das Feld Absender-Name!" form.email.error = "Bitte geben Sie eine gültige E-Mail-Adresse sein!" form.subject.error = "Bitte füllen Sie das Feld Betreff!" form.text.error = "Bitte füllen Sie das Feld Text!" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Englisch texts ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [en] ; header header.title = "Contact" ; hints on the form formhint.text = "If you want to contact me, please use the form provided below. Then I will immediately get in contact with you. Please fill all required fields!" ; form labels form.person = "Person / group: " form.name = "Your name:" form.email = "Your email address:" form.subject = "Your subject:" form.comment = "Your message:" form.button = "Send" form.captcha = "Security code:" ; confirmation text message.text = "Many thanks for your message. We will get in contact with you immediately!" ; validation messages form.name.error = "Please provide a sender name!" form.email.error = "Please provide a valid email address!" form.subject.error = "Please fill the subject field!" form.text.error = "The message may not be empty!"
Die Werte können damit z.B. per
  • <html:getstring namespace="modules::kontakt4" config="language.ini" entry="form.person" />,
  • <template:getstring namespace="modules::kontakt4" config="language.ini" entry="form.person" /> oder
  • <form:getstring namespace="modules::kontakt4" config="language.ini" entry="form.person" />
ausgelesen werden. Die Beschriftung von Formular-Controls stellt eine zweite Möglichkeit dar, sprachabhängige Texte zur Anzeige zu bringen. In diesem Fall muss im Document-Controller Einfluss auf die Beschriftung genommen werden. Dies kann mit folgenden Code passieren:
PHP-Code
// Sprachabhängige Konfiguration laden $Config = $this->getConfiguration('modules::kontakt4','language.ini'); // Referenz auf das Button-Control holen $Button = &$Form->getFormElementByName('KontaktSenden'); // Sprachabhängigen Text mit Hilfe von $this->language auslesen $Button->setAttribute('value',$Config->getSection($this->language)->getValue('form.button'));

2.3. Struktur des Moduls

Ähnlich der Struktur des Moduls "comments" wird auch dieses Software unter dem Ordner modules abgelegt. Hierzu dient der Ordner kontakt4, der wie folgt unterteilt wird:
APF-Template
/modules/ kontakt4/ biz/ data/ pres/ documentcontroller/ templates/
Der Ordner biz dient der Ablage der Business-Komponenten (je ein Domain-Objekt für die Daten des Formulars und die Empfänger), im Ordner data ist der Mapper beheimatet, der die Empfänger einliest und der Ordner pres dient zur Ablage der Controller- und Template-Dateien der Präsentationsschicht. Im Ganzen betrachtet soll das Kontaktformular aus den folgenden Dateien bestehen:

  • /modules/kontakt4/pres/templates/kontakt.html:
    Die Datei kontakt.html beinhaltet das Hauptdesign und steuert die Ausgabe von Formular oder Dankesseite mit einem <core:importdesign />-Tag.
  • /modules/kontakt4/pres/templates/formular.html:
    Die Datei formular.html beinhaltet das Formular.
  • /modules/kontakt4/pres/templates/meldung.html:
    In meldung.html ist der Inhalt der Dankesseite definiert.
  • /modules/kontakt4/pres/documentcontroller/kontakt_v2_controller.php:
    Für die Ausgabe des Formulars wird ein Document-Controller benötigt, der in der Datei kontakt_v2_controller.php enthalten ist.
  • /modules/kontakt4/biz/contactManager.php:
    contactManager.php beheimatet die Business-Komponente, die den Ablauf der Software koordiniert.
  • /modules/kontakt4/biz/ContactFormRecipient.php:
    ContactFormRecipient.php beinhaltet das Empfänger-Domain-Objekt.
  • /modules/kontakt4/biz/ContactFormData.php:
    ContactFormData.php beinhaltet das Domain-Objekt für die Formulardaten.
  • /modules/kontakt4/data/ContactMapper.php:
    Die Datei ContactMapper.php dient zur Definition der Datenschicht-Komponente, die die Empfänger aus der Konfiguration als Domain-Objekte zur Verfügung stellt.
Wie bereits erwähnt müssen darüber hinaus folgende Konfigurations-Dateien vorgehalten werden:
  • /config/modules/kontakt4/{CONTEXT}/{ENVIRONMENT}_empfaenger.ini:
    Konfiguration der Empfänger
  • /config/tools/form/taglib/{CONTEXT}/{ENVIRONMENT}_formconfig.ini:
    Texte für die Validator-Tags
  • /config/modules/kontakt4/{CONTEXT}/{ENVIRONMENT}_language.ini:
    Sprachabhängige Texte.
Die Syntax der Konfigurationsdateien wurde bereits weiter oben diskutiert, die Inhalte werden im Folgenden noch genauer beschrieben.


3. Implementierung des Moduls

In diesem Tutorial soll wieder der TOP-DOWN-Designansatz verwendet werden. Das aktuelle Kapitel beschreibt daher die oben genannten Dateien ausgehend von der Präsentationsschicht und in der Reihenfolge der Aufzählung.


3.1. Datei kontakt.html

Die Templatedatei kontakt.html definiert das Grundgerüst des Moduls. Es beinhaltet die Überschrift, die per <html:getstring />-Tag aus der Sprach-Konfigurationsdatei eingebunden wird, und einen <core:importdesign />- Tag, der einen View definiert, der entweder das Formular (Standard) oder eine Dankesmeldung anzeigt:
APF-Template
<font style="..."><html:getstring namespace="modules::kontakt4" config="language.ini" entry="header.title" /></font> <br /> <br /> <core:importdesign namespace="modules::kontakt4::pres::templates" template="[pagepart=formular]" />
Hinweis: Im Template wird das <core:importdesign />-Tag mit der pagepart-Option benutzt. Dies bedeutet, dass je nach URL-Parameter pagepart ein anderes Template aus den angegebenen Namespace eingebunden wird. Ist kein Parameter in der URL vorhanden wird die im Attribut template angegebene Templatedatei - das Formular - eingebunden.


3.2. Datei formular.html

Die hier behandelte Templatedatei enthält im Wesentlichen vier unterschiedliche Blöcke:
  • Definition des Document-Controllers (Zeile 1)
    Hier wird definiert, welcher Controller (MVC-Controller für den aktuellen DOM-Knoten) zur Transformation herangezogen wird.
  • Einbindung von weiteren TagLibs: (Zeilen 2-3)
    Um die Tag-Library <html:form /> bzw. <html:getstring /> nutzen zu können müssen diese zunächst mit einem <core:addtaglib />-Tag eingebunden werden.
  • Definition der HTML-Inhalte: (Zeilen 5-9)
    In den Zeilen 5 bis 9 wird das HTML-Grundgerüst des Formular-Views definiert. Dieser beinhaltet einen Hinweistext, der mit einem <html:getstring />-Tag eingebunden wird und einen <html:placeholder />-XML-Tag, der später vom Document-Controller mit dem Inhalt des transformierten Formulars gefüllt wird.
  • Formular: (Zeilen 11-43)
    In den Zeilen 11 bis 43 wird das Formular definiert. Dieses beinhaltet eine Validator-Gruppe, die zur Anzeige der Validierungsmeldungen genutzt wird. Die Beschriftungen werden mit dem <form:getstring />-Tag uns der oben beschriebenen Konfigurationsdatei realisiert.
APF-Template
<@controller namespace="modules::kontakt4::pres::documentcontroller" class="contact_form_controller" @> <core:addtaglib namespace="tools::form::taglib" class="HtmlFormTag" prefix="html" name="form" /> <p> <html:getstring namespace="modules::kontakt4" config="language" entry="formhint.text" /> </p> <div class="contact-form"> <html:form name="contact" method="post"> <div> <form:error id="toperror"> <div class="error-container"> <ul> </form:error> <form:listener control="AbsenderName" id="sender-error"> <li><listener:placeholder name="content" /></li> </form:listener> <form:listener control="AbsenderAdresse" id="addr-error"> <li><listener:placeholder name="content" /></li> </form:listener> <form:listener control="Betreff" id="subject-error"> <li><listener:placeholder name="content" /></li> </form:listener> <form:listener control="Text" id="text-error"> <li><listener:placeholder name="content" /></li> </form:listener> <form:listener control="captcha" id="captcha-error"> <li><listener:placeholder name="content" /></li> </form:listener> <form:error id="bottomerror"> </ul> </div> </form:error> <form:addvalidator class="TextLengthValidator" button="sendFormContact" control="AbsenderName|Betreff|Text" /> <form:addvalidator class="EMailValidator" button="sendFormContact" control="AbsenderAdresse" /> <form:addfilter class="EMailFilter" button="sendFormContact" control="AbsenderAdresse" /> <label for="contact-form-recipient"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.person" /> </label> <form:select id="contact-form-recipient" name="Empfaenger" /> <label for="contact-form-sendername"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.name" /> </label> <form:text id="contact-form-sendername" name="AbsenderName" /> <label for="contact-form-recipient-email"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.email" /> </label> <form:text id="contact-form-recipient-email" name="AbsenderAdresse" /> <label for="contact-form-subject"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.subject" /> </label> <form:text id="contact-form-subject" name="Betreff" /> <label for="contact-form-textarea"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.comment" /> </label> <form:area id="contact-form-textarea" name="Text" cols="50" rows="6"/> <div class="fullsizebox captchabox"> <label for="contact-form-captcha"> <form:getstring namespace="modules::kontakt4" config="language" entry="form.captcha" /> </label> <form:addtaglib namespace="modules::captcha::pres::taglib" class="SimpleCaptchaTag" prefix="form" name="captcha" /> <form:captcha name="captcha-control" clearonerror="true" text_id="contact-form-captcha" disable_inline="true" /> <form:addvalidator namespace="modules::captcha::pres::validator" class="CaptchaValidator" control="captcha-control" button="sendFormContact" /> </div> <div class="fullsizebox buttonbox"> <form:button name="sendFormContact" class="button"/> </div> </div> </html:form> </div>

3.3. Datei meldung.html

In der Datei meldung.html wird die Dankesmeldung definiert, die bei erfolgreichem Absenden des Formulars eingeblendet wird. In der Regel ist das ein Satz, der besagt, dass der Kunde baldige Rückantwort erhalten werden. In diesem Fall wird die Meldung aus einer Konfigurationsdatei gelesen, die einen mehrsprachigen, aber statischen Text enthält. Aus diesem Grund ist kein weiterer Document-Controller notwenig.
APF-Template
<br /> <html:getstring namespace="modules::kontakt4" config="language.ini" entry="message.text" /> <br /> <br />

3.4. Document-Controller contact_form_controller

Der Document-Controller contact_form_controller erbt vom abstrakten Document-Controller BaseDocumentController (Interface). Auf Grund der Objekt-Struktur muss dies immer gegeben sein, die übrige Gestaltung der Klasse bleibt jedoch dem Programmierer überlassen. Es ist somit jederzeit möglich eigene Methoden zu definieren und weitere eigene Klassen per import() hinzuzuladen und zu verwenden. Zu Steuerung der Ausgabe des Designs kontakt.html wird die öffentliche Methode transformContent() implementiert. Sie beschreibt, dass das Formular so lange angezeigt wird, bis alle als Pflichtfelder gekennzeichneten Eingabe-Felder mit validen Werten ausgefüllt sind (siehe Zeile 60). Tritt dieser Fall ein, so wird die Business-Schicht instanziert, das Formular abgeschickt und der Bestätigungsview (Templatedatei meldung.html) angezeigt.
PHP-Code
import('tools::link', 'LinkGenerator'); import('modules::kontakt4::biz', 'ContactFormData'); class contact_form_controller extends BaseDocumentController { public function transformContent() { $form = & $this->getForm('contact'); // generate a generic action url, to be included in various pages $action = LinkGenerator::generateUrl(Url::fromCurrent()); $form->setAction($action); // fill recipient list /* @var $recipients SelectBoxTag */ $recipients = & $form->getFormElementByName('Empfaenger'); /* @var $cM ContactManager */ $cM = & $this->getServiceObject('modules::kontakt4::biz', 'ContactManager'); /* @var $recipientList ContactFormRecipient[] */ $recipientList = $cM->loadRecipients(); for ($i = 0; $i < count($recipientList); $i++) { $recipients->addOption($recipientList[$i]->getName(), $recipientList[$i]->getId()); } if ($form->isSent() && $form->isValid()) { $formData = new ContactFormData(); /* @var $recipient SelectBoxTag */ $recipient = & $form->getFormElementByName('Empfaenger'); $option = & $recipient->getSelectedOption(); $recipientId = $option->getAttribute('value'); $formData->setRecipientId($recipientId); $name = & $form->getFormElementByName('AbsenderName'); $formData->setSenderName($name->getAttribute('value')); $email = & $form->getFormElementByName('AbsenderAdresse'); $formData->setSenderEmail($email->getAttribute('value')); $subject = & $form->getFormElementByName('Betreff'); $formData->setSubject($subject->getAttribute('value')); $text = & $form->getFormElementByName('Text'); $formData->setMessage($text->getContent()); /* @var $cM ContactManager */ $cM = & $this->getServiceObject('modules::kontakt4::biz', 'ContactManager'); $cM->sendContactForm($formData); } else { // label the button $config = $this->getConfiguration('modules::kontakt4', 'language'); $value = $config->getSection($this->language)->getValue('form.button'); $button = & $form->getFormElementByName('sendFormContact'); $button->setAttribute('value', $value); // fill listeners with the language dependent values $senderError = & $form->getFormElementByID('sender-error'); $senderError->setPlaceHolder('content', $config->getSection($this->language)->getValue('form.name.error')); $addrError = & $form->getFormElementByID('addr-error'); $addrError->setPlaceHolder('content', $config->getSection($this->language)->getValue('form.email.error')); $subjectError = & $form->getFormElementByID('subject-error'); $subjectError->setPlaceHolder('content', $config->getSection($this->language)->getValue('form.subject.error')); $textError = & $form->getFormElementByID('text-error'); $textError->setPlaceHolder('content', $config->getSection($this->language)->getValue('form.text.error')); $captchaError = & $form->getFormElementByID('captcha-error'); $captchaError->setPlaceHolder('content', $config->getSection($this->language)->getValue('form.captcha.error')); $form->transformOnPlace(); } } }

Bei näherer Betrachtung der Klasse contact_form_controller wird deutlich, dass der Document-Controller die Komponenten RequestHandler und ContactManager verwendet. Die zuerst genannte Klasse ist eine im Framework integrierte Klasse, die für die Extraktion von REQUEST-Variablen verwendet wird und nicht im Request enthaltene Variablen mit Standard-Werten belegen kann. Details zu dieser Komponente können dem RequestHandler entnommen werden. Die zweite Komponente ist die Business-Schicht des Kontaktformulars. Sie stellt der Präsentations-Schicht eine Schnittstelle zum Laden von Empfängern und Abschicken des Formulars zur Verfügung.

In der Methode transformContent() findet die Generierung der Darstellung statt. Hierzu wird eine Referenz auf das Formular-Objekt geholt und anschließend geprüft, ob das Formular abgeschickt wurde und die Eingaben valide sind. Ist das nicht der Fall, wird der oben erwähnte Platzhalter mit der Formularausgabe gefüllt. Sind die Eingaben valide, so wird ein Form-Daten-Objekt erzeugt und mit Werten gefüllt. Anschließend wird die Business-Komponente mit Hilfe der privaten Methode getServiceObject() erzeugt und die Methode sendContactForm() mit dem DomainObjekt ContactFormData als Parameter aufgerufen und das Formular abgesendet. Das Verschicken der Daten per Mail und die Weiterleitung wird dabei von der Businessschicht übernommen.

3.5. Klasse ContactManager

Die Klasse ContactManager ist eine Implementierung der Business-Schicht. Sie kapselt die eigentliche Geschäfts-Logik der Anwendung und kommuniziert mit weiter unten liegenden Schichten (Daten-Schicht oder weitere Treiber-Schichten). Im Fall des Kontakt-Formulars wird in der Business-Schicht das Formular abgesendet oder Empfängerdaten geladen. Dazu stehen der Präsentations-Schicht zwei öffentliche Methoden zur Verfügung: sendContactForm() um ein Formular abzusenden und loadRecipients() um Empfänger zu laden. Die Schnittstelle zwischen diesen beiden Schichten bilden die Domain-Objekte ContactFormData und ContactFormRecipient.
PHP-Code
import('modules::kontakt4::biz', 'ContactFormData'); import('modules::kontakt4::biz', 'ContactFormRecipient'); import('tools::link', 'LinkGenerator'); import('tools::http', 'HeaderManager'); class ContactManager extends APFObject { public function sendContactForm(ContactFormData $formData) { $cM = &$this->getServiceObject('modules::kontakt4::data', 'ContactMapper'); // set up the mail sender $MAIL = &$this->getAndInitServiceObject('tools::mail', 'mailSender', 'ContactForm'); $recipient = $cM->loadRecipientPerId($formData->getRecipientId()); $MAIL->setRecipient($recipient->getEmailAddress(), $recipient->getName()); $Text = 'Sehr geehrter Empfänger, sehr geehrte Empfängerin,'; $Text .= "\n\n"; $Text .= $formData->getSenderName() . ' (E-Mail: ' . $formData->getSenderEmail() . ') hat Ihnen folgende Nachricht über das Kontaktformular zukommen lassen:'; $Text .= "\n\n\n"; $Text .= $formData->getMessage(); $MAIL->setContent($Text); $MAIL->setSubject($formData->getSubject()); // send mail to notify the recipient $MAIL->sendMail(); $MAIL->clearRecipients(); $MAIL->clearCCRecipients(); $MAIL->clearContent(); $MAIL->setRecipient($formData->getSenderEmail(), $formData->getSenderName()); $Text = 'Sehr geehrter Empfänger, sehr geehrte Empfängerin,'; $Text .= "\n\n"; $Text .= 'Ihre Anfrage wurde an die Kontaktperson "' . $recipient->getName() . '" weitergeleitet. Wir setzen uns baldmöglich mit Ihnen in Verbindung!'; $Text .= "\n\n"; $Text .= 'Hier nochmals Ihr Anfragetext:'; $Text .= "\n"; $Text .= $formData->getMessage(); $MAIL->setContent($Text); $MAIL->setSubject($formData->getSubject()); // send mail to notify the sender $MAIL->sendMail(); // redirect to the thanks page to avoid F5 bugs! $link = LinkGenerator::generateUrl(Url::fromCurrent()->mergeQuery(array('contactview' => 'thanks'))); $urlRewriting = Registry::retrieve('apf::core', 'URLRewriting'); if ($urlRewriting != true) { $link = str_replace('&', '&', $link); } HeaderManager::forward($link); } public function loadRecipients() { $cM = & $this->getServiceObject('modules::kontakt4::data', 'ContactMapper'); return $cM->loadRecipients(); } }
In den ersten beiden Zeilen werden wiederum Komponenten aus dem Framework eingebunden, die später für den Mailversand (mailSender)und das Generieren von Links (LinkGenerator) verwendet werden.
In der Methode sendContactForm() werden zwei ServiceObjekte initialisiert, die für den Versand notwendig sind: die Datenschicht um das ausgewählte Empfänger-Objekt zu laden und der mailSender um die Bestätigungs- und Benachrichtigungs-Mails zu versenden.
Die Methode loadRecipients() ist der Service für die Präsentationsschicht, die die Empfänger-Objekte läd.


4. Klasse ContactMapper

Die Klasse ContactMapper ist eine Implementierung des DataMapper-Patterns und dient der Business-Schicht um Daten aus der Empfänger-Konfigurationsdatei in Form von Domain-Objekten zur Verfügung zu stellen. Dazu läd der Mapper die Daten zunächst mit Hilfe der Funktion getConfiguration() aus der Konfigurations-Datei und mappt dies anschließend in Empfänger-Domänen-Objekte (ContactFormRecipient).
PHP-Code
import('modules::kontakt4::biz','ContactFormData'); import('modules::kontakt4::biz','ContactFormRecipient'); class ContactMapper extends APFObject { public function loadRecipients(){ // read config $Config = $this->getConfiguration('modules::kontakt4','empfaenger.ini'); // initialize return array $Recipients = array(); // parse config and generate recipients foreach($Config->getSectionNames() as $name){ $Count = count($Recipients); $Recipients[$Count] = new ContactFormRecipient(); // id preg_match("/Kontakt ([0-9]+)/i",$name,$Matches); $Recipients[$Count]->set('oID',$Matches[1]); // name $Recipients[$Count]->set('Name',$Config->getSection($name)->getValue('EmpfaengerName')); // email $Recipients[$Count]->set('Adresse',$Config->getSection($name)->getValue('EmpfaengerAdresse')); } // return recipient list return $Recipients; } public function loadRecipientPerId($Id){ $Rec = $this->loadRecipients(); if(!is_array($Rec)){ return array(); } else{ for($i = 0; $i < count($Rec); $i++){ if($Rec[$i]->get('oID') == $Id){ return $Rec[$i]; } } } } }
Die Konfigurationsdatei selbst ist mit mehreren Sektionen der Form
APF-Template
[Kontakt <em>([0-9]+)</em>] EmpfaengerName = "<em>([A-Za-z0-9,.-_ ]+)</em>" EmpfaengerAdresse = "<em>([A-Za-z0-9.-_@]+)</em>"
aufgebaut. Die Methode loadRecipients() mappt dabei jede Sektion in ein Domain-Objekt (ContactFormRecipient) und liefert eine Liste dieser zurück. Jeder Empfänger kann beim Versenden des Formulars an Hand seiner eindeutigen ID (siehe Sektionsnamen) referenziert und per loadRecipientById() geladen werden.
Wird als Quelle keine Konfigurations-Datei, sondern eine Datenbank verwendet, muss lediglich die Implementierungen der Daten-Schicht-Methoden dahin geändert werden, dass die Daten aus der Datenbank statt aus der Datei gelesen werden.


Kommentare

Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
« 1   »
Einträge/Seite: | 5 | 10 | 15 | 20 |
1
Christian 12.10.2008, 23:12:17
Hallo Reiner,

aktuell wird keine Prüfung unternommen, von welchem Server das Formular abgeschickt wird. Lediglich ein Bild-CAPTCHA schützt das Formular, was letztlich einen ähnlichen Effekt hat.

Wie würdest du eine derartige Prüfung implementieren? Wollen wir im Forum weiter diskutieren?

Viele Grüße,
Christian
2
Reiner Rottmann 18.08.2008, 14:32:39
Unterstützt das Formular auch eine Verifizierung, dass Anfragen nur vom Webserver und keinen anderen Seiten kommen dürfen? Bei der Auswahl eines Webformulars ist es imho besonders wichtig, dass dieses nicht für Spam verwendet werden kann...