Vom: 17.04.2012

Formulare in Pimcore einfach erstellt

Pimcore liefert mit dem unterliegenden Zend Framework und dem Formbuilder-Plugin von Alexandre Delattre eine komfortable Möglichkeit, eigene Formulare zu erstellen und zu behandeln. Die Zend Forms sind die eierlegende Wollmilchsau, die alles bietet von der Definition der Felder selbst über die Verifizierung der Inhalte und ihrer Bereinigung bis zu Ihrer Verarbeitung - und, nicht zuletzt, ihrer Darstellung im Browser. Diese Darstellung erfolgt mit dem Strukturmuster der Decorator, jedes Element "weiss", wie es dargestellt werden sollte und das Formular kann "sich selbst" ausgeben. Das ist sehr angenehm und praktisch, da für einfache Anwendungen keine weitere Schritte unternommen werden müssen als ein <?php print $form; ?>. Hier liegt aber auch die Krux, denn wirklich aufwändige Designs umzusetzen erfordert einen unverhältnismäßig hohen Aufwand zur Definition der oftmals für jedes Element individuellen Decorator. Man kann aber auch den umgekehrten Weg gehen und das Formular "zu Fuss" programmieren und sich nur bei den benötigten Elementen des Formulars bedienen. Genau das soll in diesem Beispiel geschehen, zusammen mit ein paar anderen Tricks und Kniffen. Zuerst muss natürlich das Formular im Formbuilder Plugin gestaltet werden. Hierzu fügt man einfach die benötigten Form Elemente zusammen und stattet diese mit sinnvollen Validatoren zur Prüfung erlaubter Eingaben und Filtern zur Entfernung unerwünschter Inhalte aus. Ist das Formular erstellt und gespeichert, kann man es im Controller seiner View zuweisen:

public function uploadAction () {
  $formbuilder = new Formbuilder_Frontend();
  $form = $formbuilder->getForm("onlinebewerbung");
  $this->view->form = $form;
}

In der View könnte man es nun theoretisch einfach nur ausgeben und die Ausgabe wäre damit erschöpfend behandelt:

<?php print $this->form; ?>

Hier wollen wir aber eingreifen und jedes Feld per Hand in individuellem HTML/PHP-Code ausgeben. Im Wesentlichen besteht ein Element hierfür aus den Komponenten Label, also der Feldbeschriftung, ViewHelper für die Darstellung des eigentlichen Eingabelemenents und dem Error für den Fall, das ein Validator eingreift. Die Ausgabe erfolgt nun über entsprechende Methoden:

<?php $form = $this->form; ?>
<?php print $form->anrede->renderLabel() ?>  <?php print $form->anrede->renderViewHelper() ?><?php print $form->anrede->renderErrors() ?>

Was am Label nicht per Default dranhängt ist die Anzeige ob die Eingabe eines Feldes erforderlich ist. Der Label-Decorator kennt aber ein "requiredSuffix" mit dem man bestimmen kann, was das Label in diesem Fall rendern soll. Nun muss man nur noch das ausgefüllte Formular verarbeiten. Dabei bedienen wir uns eines Tricks um die Code-Workflow übersichtlich und gering zu halten. Wird die Seite einfach nur so (also per GET) aufgerufen, liegt in der Regel keine Wertübermittlung vor und das Formular soll nur ausgegeben werden. Als action gibt man im form nun die URL des forms an - es ruft sich also selbst auf, vorzugsweise mit einem POST! Diesen POST kann man nun als Signal für die Weiterverarbeitung auswerten; if ($this->getRequest()->isPost()). Das Formular muss nun auf korrekte Eingabgen geprüft werden: if ($form->isValid($_POST)) {. Bei dieser Prüfung setzt Zend_Form, falls nötig, die entsprechenden Fehlermeldungen. Nur bei erfolgreicher Prüfung verarbeitet man also weiter, kommt die Prüfung mit dem Ergebnis false zurück soll der Code wieder die Darstellung übernehmen - nur mit dem Unterschied, dass das Form mit den notwendigen Fehlermeldungen ausgestattet wurde, die nun mittels renderErrors() im View dargestellt werden. War die Prüfung dagegen erfolgreich wird die Eingabe geeignet verarbeitet und die Ausführung auf einer Folgeseite mittels _redirect($url) fortgesetzt.

public function uploadAction () {
  $formbuilder = new Formbuilder_Frontend();
  $form = $formbuilder->getForm("onlinebewerbung");

  // Das Formular verarbeiten wenn es per POST übermittelt wurde
  if ($this->getRequest()->isPost()) {

    // Ist die Eingabe valide?
    if ($form->isValid($_POST)) {
      $values = $form->getValues(); // Alles OK, die Werte abholen

      // Hier nun was damit anfangen

      $this->_redirect("/danke"); // Redirect an die Folgeseite
      // Hier kommen wir nun nicht mehr hin!
    }
  }
  // Das Formular wird zum ersten Mal aufgerufen oder die Eingabe war nicht valide

  // Die Elemente, die ausgefüllt werden müssen,
  // mit einem "*" nach dem Label rendern
  foreach ($form->getElements() as $formelement) {
    $decorator = $formelement->getDecorator('label');
    if (is_object($decorator)) {
      $decorator->setOption('requiredSuffix',' *');
    }
  }
  $this->view->form = $form;
}

Ein paar Klippen gilt es vielleicht noch zu umschiffen. Das Element für Fileuploads kennt keine renderLabel() Methode, man kann es nur vollständig (inklusive Label) mit render() ausgeben lassen. Muss man gewisse Designvorgaben umsetzen und z.B. nach dem Label einen ":" ausgeben, kann man den Label-Decorator entsprechend konfigurieren:

foreach ($form as $element) {
  $label = $element->getDecorator("Label");
  if (is_object($label)) $label->setOption("separator", ":"); // nach jedem Label einen : rendern.
}

Auch lassen sich leider Captchas nicht "zerlegen" sondern nur komplett rendern, eigene Umsetzungen sind hier nur schwer möglich - dem widme ich aber noch einen eigenen Blogeintrag :-)