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.
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.
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
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
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
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
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