Plone kommt mit dem CMF Form Controller-Produkt, mit dem die Abläufe zwischen Formularen und Skripten geregelt werden können. Gerade für komplexe Abläufe ist es sehr hilfreich, unterstützt jedoch keine Zope3-Views und kann daher nur in Skin-Layern definiert werden.
Schauen wir uns nun als Beispiel Plone’s Send this page to someone-Formular an, das in CMFPlone/skins/plone_forms/sendto_form.cpt definiert ist. Dabei steht der cpt-Suffix für Controller Page Template:
<div metal:fill-slot="main" tal:define="errors options/state/getErrors;"> ... <form name="sendto_form" class="enableAutoFocus" action="sendto_form" method="post" enctype="multipart/form-data" tal:attributes="action string:$here_url/$template_id"> ... <div class="field" tal:define="error errors/send_to_address|nothing;" tal:attributes="class python:test(error, ``field error``, ``field``)"> ... <div class="formControls"> <input class="context" type="submit" name="form.button.Send" value="Send" i18n:attributes="value label_send;" /> </div> ... </form>
- Zunächst fällt auf, dass eine Variable errors definiert wird, die das Auffinden von Validierungsfehlern erlaubt.
- Dann sehen wir, dass das Formular – wie bei CMFFormController üblich – wieder auf sich selbst verweist.
- Schließlich erkennen wir die versteckte Variable form.submitted, wobei das Controller Page Template überprüft, ob das Formular einfach aufgerufen oder bereits abgeschickt wurde.
CMFFormController benötigt zur Auswertung des Formulars eine korrespondierende Datei sendto.cpy.metadata im selben Verzeichnis:
[default] title=Send this page to somebody [validators] validators=validate_sendto [actions] action.success=traverse_to:string:sendto action.failure=traverse_to:string:sendto_form
Schauen wir uns nun die Validatoren und Aktionen genauer an.
Validatoren angeben
Allgemein lassen sich für Für Controller Page Templates folgendermaßen Validatoren angeben:
[validators] validators = validate_script1, validate_script2
Diese Angabe startet zwei Prüfskripte: zunächst validate_script1 , dann validate_script2 . Ein Prüfskript untersucht die Formulardaten wobei Fehler dem Form Controller Status hinzugefügt werden.
Objekttyp-spezifische Validierung
Soll die Validierung vom Objekttyp Document verschieden sein von der des Objekttyps Image sieht die Metaangabe so aus:
validators.Document = validate_script1 validators.Image = validate_script2
Button-spezifische Validierung
Kommen im Formular mehrere Buttons (Tasten) vor, z.B.:
<input type="submit" name="form.button.button1" value="Value1" /> <input type="submit" name="form.button.button2" value="Value2" />
können für diese auch unterschiedliche Validierungen angegeben werden:
validators.button1 = validate_script1 validators.button2 = validate_script2
Aktionen angeben
Für Controller Page Templates lassen sich auch Aktionen angeben, z.B.:
[actions] action.success = traverse_to:string:script1
Haben die Prüfskripte den Status success ausgegeben, wird die Aktion traverse_to mit dem Argument string:script1 aufgerufen.
Schlägt ein Prüfskript fehl, wird gemäß den Standardeinstellungen das Formular erneut geladen.
Wie bei Validatoren kann auch bei Aktionen zwischen Dokumenttypen und Buttons unterschieden werden:
action.success.Document = traverse_to:string:document_script action.success.Image = traverse_to:string:image_script
action.success.button1 = traverse_to:string:script1 action.success.button2 = traverse_to:string:script2
Folgende Aktionen sind möglich:
- redirect_to
- redirect_to_action
- traverse_to
- traverse_to_action.
Dabei rufen die traverse_to-Aktionen direkt ein Template oder Skript auf dem Server auf, wohingegen die redirect_to-Aktionen eine Weiterleitung des Browsers bewirken. Normalerweise werden die Zwischenschritte mit traverse_to-Aktionen und nur der letzte Schritt mit einer redirect_to-Aktion angegeben, sodass die Angabe der URL im Browser die aktuelle Seite wiedergibt. So ist z.B. in unserem Beispiel in sendto.cpy.metadata folgendes angegeben:
[validators] validators=validate_sendto [actions] action.success = redirect_to_action:string:view action.failure = redirect_to_action:string:view
Validator-Skripte schreiben
Schauen wir uns nun das Validator-Skript validate_sendto.vpy genauer an, auf das in sendto.cpy.metadata verwiesen wurde:
## Controller Script Python "validate_sendto" ##bind container=container ##bind context=context ##bind namespace= ##bind script=script ##bind state=state ##bind subpath=traverse_subpath ##parameters=send_to_address='',send_from_address='' ##title=validates the email adresses from Products.CMFPlone import PloneMessageFactory as _ plone_utils=context.plone_utils if not send_to_address: state.setError('send_to_address', _(u'Please submit an email address.'), 'email_required') ... if state.getErrors(): context.plone_utils.addPortalMessage(_(u'Please correct the indicated errors.'), 'error') return state.set(status='failure') else: return state
Aktionen schreiben
Ist die Validierung erfolgreich, fährt der CMFFormController, wie in sendto_form.cpt.metadata angegeben mit dem Skript sendto.cpy fort. Dieses Skript gibt schließlich den Wert für state aus:
## Controller Python Script "sendto" ##bind container=container ##bind context=context ##bind namespace= ##bind script=script ##bind state=state ##bind subpath=traverse_subpath ##parameters= ##title=Send an URL to a friend ## REQUEST=context.REQUEST ... if not mtool.checkPermission(AllowSendto, context): context.plone_utils.addPortalMessage(_(u'You are not allowed to send this link.'), 'error') return state.set(status='failure') ... context.plone_utils.addPortalMessage(_(u'Mail sent.')) return state