vmLogo mediaDESIGN 200Aufgabenstellung

In diesem Beitrag geht es darum, wie man in einem Joomla-Projekt ein Kontaktformular erstellen kann in welches für bereits registrierte VirtueMart-Webshop-Benutzer die Benutzerdaten vorausgefüllt werden. D.h. beim Aufruf des Scriptes sollen die Daten aus der VM-UserInfo-Tabelle verwendet werden. 

 

Vorabinformation zu BreezingForms in dieser Sache

Ich hatte mit BreezingForms bei der Umsetzung diese Vorhaben reichlich Mühe die notwendigen Erkenntisse über Zusammenhänge und Wirkungsweisen zu erschließen. Es ist schlecht dokumentiert und teilweise wichtige Informationen lassen sich aus der Dokumentation/WiKi oder Foren nicht erlesen. Ein Grundübel dabei, und das für eine Komponente die Lizenzgebühren kostet ist, dass z.B. nirgens detailiert Informationen darüber erhältlich sind welcher der 3-Betriebsmodies von BreezingForms welche Features anbietet. Die wenigen Ausführungen dazu lassen vermuten, dass es sich nur um Features handelt die den Aufbau/Erstellung von Formularen betreffen. Das stimmt so nicht. Ich musste die Erkenntnis machen, dass viele Funktionen in den z.B. in den Foren wie selbstverständlich gesprochen wird, nur im QuickMode funktionieren.



 

Ich hatte in Projekten Formulare durchweg im EasyModus erstellt - schien mir praktikabel. Nach dem ich durch viele gescheiterte Test dann doch mal den Versuch machte, ob beschriebene Scriptbeispiele oder "Pieces" im QuickModus laufen - was sie prompt taten, war es zu spät. Eine Konvertierungsmöglichkeit von Formularen vom EasyModus zu QuickModus gibt es nicht! Chansenlos, weil selbst ein Anpassung z.B. über Datenbank-Eingriffe unmöglich sind, weil die Formularbeschreibungen komplett komprimiert/verschlüsselt sind.

Fazit: EasyMode vergessen, QuickModus verwenden!

Für mein Vorhaben war es zu spät. Ich wollte die Formulare auch nicht alle neu aufbauen. Um oben beschriebene Aufgabenstellung umzusetzen konnte ich also auf Funktionen die nur im QuickModus laufen nicht zugreifen und musste eine spezielle Lösung schaffen, die nun nachfolgend beschrieben ist.

 

Vorab etwas Grundwissen zum BreezingForm - Scripting

Diese Infos sind auch auf den Crosstec-Seiten erhältlich.

Es gibt  zweierlei Scriptformen. Zum einen die sogenanten Skripte (scripts) und zum anderen die Pieses (Teile). Für beides gibt es die Möglichkeit solche als wiederverwendbare Code-Funktionen in den Skript- und Teile-Verwaltungen (Funktionsbibliotheken) für die Mehrfachverwendung abzulegen und zu verwalten, oder diese quasi für die Einmalnutzung an der entspr. Stelle z.B. für ein Formular als Formulareigenschaft oder für Formularelemente abzulegen. Diese Funktionen können zu unterschiedlichen Zeitpunkten oder Ereignissen aufgerufen werden, z.B. bei Formular- oder Feldinitialisierung oder danach oder als Validierung etc. Hier ist BreezingForms sehr flexibel und ausgereift.

Skirpte sind überlicherweise JavaScript-Funktionen, wären unter Teilen typischweise PHP-Sequenzen ausgeführt werden können. Beides lässt sich aus elegant vermischen wie in meinem nachfolgenden Beispiel zu erkennen.

Sequenzen, die als Skript eingebunden werden, beginnen üblicherweise mit einer JavaScript-Funktionsdeklaration. Sollen z.B. in das JavaScript dynamisch Inhalte eingefügt werden, dann kann das per PHP erfolgen und muss dann natürlich mit <?php ... ?> gekapselt werden.

Genau anders verhält es sich bei Teilen (Pieces). Diese verden als PHP-Code angenommen weil mit eval() interprätiert. Folglich wir also sofort mit dem ersten PHP-Befehl begonnen. Ohne vorangestellter PHP-Kapselung.

Außerdem lassen sich alle Scripte noch in Paketen organisieren. Das ist besonders dann vorteilhaft, wenn man eine Sammlung von Scripten zwischen Projekten austauschen will, dann diese Pakete lassen sich exportieren und Importieren. Ein Paket, welches mit der Installation von BF vorhanden ist, ist das Paket "FF".

 

Mein Skript ff_preFillKontaktFormUsersInfo()

Alle Ausführung beziehen sich auf die Version 1.7.3 von BF.
Ich setze voraus, dass bereits ein Kontaktformuar durch Sie angelegt wurde, das soll hier nicht Gegenstand sein. In diesem Formular muss es ein SelectListen-Feld geben mit dem Titel KontaktLandKz. Für diese Feld steht in den Optionen nicht drin - also leer lassen, denn das wird ja durch unser Script mit Elementen befüllt!

Eigentlich wollte ich das Kontaktformular über ein Piece also per PHP vorbefüllen. Der Grundansatz besteht hier darin, dass schon beim Erzeugen der Formularfelden beim Durchlaufen des BreezingForms-Prozess-Scriptes (facileforms.process.php) die Felder mit ihren values versehen werden. Dafür hat BF wie oben erwähnt Schnittstellen vorgesehen, die aber leider nur im QuickModus vollständig laufen. Das zu nutzen ist besonders elegant, weil 1. nicht zusätzlich JavaScript-Sequenzen in den Seiten-Quellkode geschrieben werden müssen, 2. sich alles komplett auf PHP-Basis abspielt.

Nun gut mir blieb nur die Skripte-Variante :-(. 

Dazu wir folgt vorgehen:

  1. Die Komponente BF aufrufen und den Link "Skripte verwalten" anklicken.
  2. Es erscheint die liste der vorhandenen Skripte. Sollte die Liste leer sein, müssen Sie über der Liste das Paket "FF" auswählen. Im oberen Menü auf (+) neu klicken.
  3. Im Skriptbearbeitungsdialog-Kopf nur beispielsweise folgende Eigenschaftsoptionen eingeben:
    Titel: prefill KontaktForm with VMUserInfos
    Veröffentlicht: ja
    Paket: FF
    Name: ff_preFillKontaktFormUsersInfo (wichtig!)
    Typ: Formular Initialisierung
    Beschreibung: Befüllt das Kontaktformular beim Aufruf mit den bekannten Daten eines eingeloggten VM-Users.
  4. Nun der wichtig Inhalt für das COde-Eingabefeld. Hier hinein kopieren nachfolgenden Script.
  5. Das ganz speichern.
  6. Wir landen wieder in der Listendarstellung von "Skripte verwalten" und wählen hier den Kopflink "Formulare verwalten".
  7. In der Liste wählen wir und Kontaktformular und gehen dort sofort auf den Kopfbutton "Formulareinstellungen".
  8. Im modalen Formularbearbeitungsdialog wählen wir den Reiter Scripte. In der Gruppe "Initialisierungsskript" wähen wir den Radiobutton "Bibliothek". In der Pulldownliste Skript sollte unser eben angelegtes Script aufgeführt sein, welches wir dann also auswählen können. Das waren hier alle notw. Einstellungen.
  9. Speichern und testen des Formulars.

Hier nun das einzufügende Skript:

 

function ff_preFillKontaktFormUsersInfo() {
  <?php
  $db =& JFactory::getDBO();
  $userinfos = null;
  $uid =& JFactory::getUser()->get('id');
  $query = 'SELECT country_name, country_3_code FROM #__vm_country';
  $db->setQuery($query);
  $countries = $db->loadObjectList();
  if ($db->getErrorNum()) { JError::raiseWarning ( 500, $db->stderr() ); }
  if ($uid == 0) {
    echo "function ff_EasyFormKontakt_init() {}";
    JError::raiseNotice ( 500, 'Wenn Sie ein registrierter Benutzer sind, sollten Sie sich <a href="/component/virtuemart/?page=checkout.index&Itemid=91">anmelden</a>, dann wird das Formular für Sie vorausgefüllt.');
    $countrieslist = '<option selected="selected" value="">Land wählen</option>';
    foreach ($countries as $country) {
      $countrieslist .= '<option value="'.$country->country_3_code.'">'.$country->country_name.'</option>';
    }
    return
     "ff_getElementByName('KontaktLandKz').innerHTML = '".$countrieslist."';\n";
    } else {
    $query = 'SELECT * FROM #__vm_user_info WHERE user_id = '.$uid.' AND address_type = "BT"';
    $db->setQuery($query);
    $userinfos = $db->loadObject();
    if ($db->getErrorNum()) JError::raiseWarning ( 500, $db->stderr() ); 
    $countrieslist = '<option value="">Land wählen</option>';      foreach ($countries as $country) {
      $isUserCountry = ($userinfos->country == $country->country_3_code) ? ' selected="selected" ' : ' ';
      $countrieslist .= '<option'.$isUserCountry.' value="'.$country->country_3_code.'">'.$country->country_name.'</option>';  
    }
    return
    "ff_getElementByName('KontaktLandKz').innerHTML = '".$countrieslist."';\n".
    "ff_getElementByName('KontaktFirma').value = '". $userinfos->company. "';\n".
    "ff_getElementByName('KontaktFirma2').value = '". $userinfos->vm_firma. "';\n".
    "ff_getElementByName('KontaktStrasse').value = '". $userinfos->address_1 ." ". $userinfos->address_2. "';\n".
    "ff_getElementByName('KontaktPLZ').value = '". $userinfos->zip. "';\n".
    "ff_getElementByName('KontaktOrt').value = '". $userinfos->city. "';\n".
    "ff_getElementByName('KontaktAnrede').value = '". $userinfos->title. "';\n".
    "ff_getElementByName('KontaktVorname').value = '". $userinfos->first_name. "';\n".
    "ff_getElementByName('KontaktNachname').value = '". $userinfos->last_name. "';\n".
    "ff_getElementByName('KontaktFunktion').value = '". $userinfos->vm_funktion. "';\n".
    "ff_getElementByName('KontaktTelefon').value = '". $userinfos->phone_2 ." ". $userinfos->phone_1. "';\n".
    "ff_getElementByName('KontaktFax').value = '". $userinfos->vm_faxvorwahl ." ". $userinfos->fax. "';\n".
    "ff_getElementByName('KontaktEMail').value = '". JFactory::getUser()->get('email'). "';\n";
   } // endif user	
   ?>
}

Natürlich müssen die im unteren Teil aufgeführten Felder an die Situation in Ihrem Formular angepasst werden, die sind hier nur beispielhaft.

 

Ein kurze Scripterleuterung

  • Die Länderliste wird aus der VirtueMart-Tabelle jos_vm_country geladen
  • Das Script verhält sich bei der Ausgabe der Länderliste unterschiedlich, je nach dem ob der Nutzer eingeloggt ist oder nicht. Ist der User bekannt, dann wird in der Länderliste der Eintrag als selected gekennzeichnet der dem Land des User entspricht, anderenfalls wird der erste Eintrag "Bitte Land wählen" selected.
  • Alle normalen Text/Textarea/Input-Felder des Formulars werden über die JavaScript-Funktion ff_getElementByName().value befüllt. Eine Funktion die BF mitbringt. Die Funktion ermittelt anhand eines BF-Feldbezeichnung die entsprechende ID des Formularfeldes, so wie im Formular tatsächlich verwendet um das Formularfeld dann über die ID anzusprechen.
  • Das Listenfeld wird über die Methode .innerHTML befüllt und zwar mit den fertigen <option>-Tags aus der Variablen $countrieslist.
  • Wer sein Fromular/Script mehrsprachig will sollte noch die Meldungen in Sprachdateien auslagern.

 

Kleine Zugabe - Script als Piece für QuickModus 

Ja wenn es noch interessiert, will ich hier gleich auch noch meinen für EasyMode-Formulare gescheiterten Versuch für das Vorbefüllen des Formulars darstellen, der aber eben nur in QuickMode-Formularen funktioniert.

Eingebunden wird dies nach oben beschriebenen Prinzip, entweder über die Teile-Verwaltung oder direkt als Spezial-Teil in den Formulareigenschaften:

 

$this->execPieceByName('ff_InitLib');
$db =& JFactory::getDBO();
$query = 'SELECT country_name, country_3_code FROM #__vm_country';
$db->setQuery($query);
$countries = $db->loadObjectList();
if ($db->getErrorNum()) { JError::raiseWarning ( 500, $db->stderr() ); }
$uid =& JFactory::getUser()->get('id');
if ($uid == 0) {
...
} else { $query = 'SELECT country FROM #__vm_user_info WHERE user_id = '.$uid.' AND address_type = "BT"'; $db->setQuery($query); $usercountry = $db->loadResult(); if ($db->getErrorNum()) JError::raiseWarning ( 500, $db->stderr() ); } $countrieslist = ""; foreach ($countries as $country) { $isUserCountry = ($usercountry == $country->country_3_code) ? 1 : 0; $countrieslist .= "{$isUserCountry};{$country->country_name};{$country->country_3_code}"."\n"; } function ff_setSelectList($name, $value) { global $ff_processor; for ($r = 0; $r < $ff_processor->rowcount; $r++) { $row =& $ff_processor->rows[$r]; if ($row->name == $name) $row->data2 = $value; unset($row); } } ff_setSelectList('KontaktLandKz', $countrieslist ); $value = $countrieslist; return $countrieslist;  

 

Also das ist eigentlich der Königsweg. Aber Achtung! In diesem Script fehlt noch die Behandlung für den Fall, dass der User nicht eingeloggt ist ($uid == 0). Das kann man analog aus dem verherigen Script übernehmen.

Erwähnenswert ist hier die PHP-Methode ff_setSelectList() die die Selektionslistenelemente in ff_processor einträgt. Dazu findet man weiterführende Informationen im crosstec-Forum.

 

Ergänzung: BreezingForms-Radio-Buttons-Gruppen vorbefüllen

Hier noch ein kleines Extra, welches nicht so einfach zu lösen ist in BreezingForms, nämlich das Vorbefüllen von RadioButton-Gruppen mit dem Element als checked, welches dem DB Eintrag in der VM-User-Infos-Tabelle entspricht. Hier habe ich bei mir z.B. eine Unterscheidung nach Kundentyp mit den möglichen Einträgen privat oder geschäftlich eingefügt. Im Kontaktformular sollen also auch diese Informationen korrekt aus der DB-Tabelle ausgelesen und vorselectiert sein.

Die erste Stolperfalle auf die wir hierbei stoßen, ist das Anlegen der Breezing-Forms-Radiobuttons im EasyMode. Es kann keine eigentlich überliche Gruppe angelegt werden, sondern es werden einfach mehrere Radio-Button-Objekt erstellt, die jedoch umbeding den gleichen Namen erhalten müssen. Dadurch entsteht quasi die notwendige Gruppierung dieser Buttons. Lediglich deren Inhalte / values unterscheiden sich.

Der nächste Stolperstein, der uns dabei das Leben schwer macht, ist was BreezingForms daraus macht. Alle Radiobuttons erhalten die gleichen Merkmale in Bezug auf id, name und class - wie also soll man nun per JavaScript den richtigen Radiobutton mit den Attribut checked versehen? Uns bleibt dafür schließlich nur der Inhalt, also das Attribut value. Um programmiertechnisch hieraus keine riesen Umstand zu machen, nutzen wir einfach die Suchfunktion von jQuery. Die fertige Einfügung in unser o.g. Script-Schnippselchen sind dann so aus:

...
    "ff_getElementByName('KontaktLandKz').innerHTML = '".$countrieslist."';\n".
    "jQuery(document).ready(function(){ \n".
        "jQuery(\"input:radio[name='ff_nm_privatgewerblich[]'][value='".$userinfos->vm_kundentyp."']\").attr('checked','checked') \n".
    " }); \n".
    "ff_getElementByName('KontaktMarksKdNr').value = '". $userinfos->vm_kdnr. "';\n".
...

Kurze Erläuterung: Wir suchen per jQuery nach input.radio-Buttons mit den name ff_nm_privatgewerblich (welches zunächst einmal alle diese Gruppe sind) und innerhalb dieser nach dem einzigen der als Inhalt den value enthält der auch unsem Datenfeld vm_kundentyp für diesen Kunden entspricht. Über die Methode attr, weisen wir das Attribut checked mit dem Wert checked zu.

Elegant ist, dass jQuery hierbei gleich evtl. schon gesetzt Vorselektierungen aufhebt und nur unser Radiobutton als checked übrig bleibt.

 

 

Wenn Ihnen dieser Beitrag geholfen und viel Zeit gespart hat, zeigen Sie sich erkenntlich: Über einen Klick auf Google+1 oder Rückmeldungen freue ich mich. Zeigen Sie mir, dass sich die Mühe für die Beitragerstellung gelohnt hat. Schenken Sie auch den Produktwerbungen Ihre Beachtung, denn damit wird mein Aufwand für diese Beiträge refinanziert.