Often, you want to leave a form but come back later with the already filled in values intact.
This happens, e.g., for form validation. When the validation fails, you will want to redisplay the form together with an appropriate error indication. An alternative here would be to put the validation code in the form itself and ensure, it is not activated for the first form entry (you could use a hidden variable for this purpose).
Another case are forms with complex input entries which require special support to be filled. When you leave the form to get this support, the form values provided so far must be saved in order to be available later, when you come back with the new value for the complex entry.
The dispatcher provides uniform support for these use cases. It controls a form and manages the form data for it. This includes initialization, saving data in a session object, dispatching to various destinations and restoring the saved values, when the form is reentered. Furthermore, it avoids problems with HTML checkbox and multiple selection handling.
A form dispatcher is used to manage the variables of a form. It
provides services for form initialization, form update and the
dispatch out of the form to various form actions. During dispatch,
the current form values are saved in a session object. When the
form is updated, the data is put back into
REQUEST.form
and updated with the new values provided
by update
.
A form dispatcher works with (at least) the following objects:
the id of the form controlled by the dispatcher
The dispatcher calls this object like a DTML method (or through
mapply
) after REQUEST.form
and
REQUEST.other
have been set up.
The default is Client
.
the description of the managed form fields.
The dispatcher calls this object like a DTML method. The call should return either a list of form value descriptions or a dictionary thereof. Each description is a dictionary describing various aspects managed by the dispatcher.
The default is ClientDescription
the id of a session managing object.
This object is used to save the current form values during dispatch.
The default is FSSession
.
the key to use for saving the current form values in the session object.
The default is the dispatchers physical path.
The form dispatcher supports the following use cases:
new
the form is used to create a new object.
The initial values of form variables are not taken from the
environment unless the form description contains an explicit
init
or fixed
description to this effect.
Other form variables are empty (depending on
dtype
).
edit
the form is used to edit an existing object.
Most form variable values are taken from the environment. Only
fixed
values are taken from the description.
show
render with currently remembered values.
This method is used, when the Dispatcher is part or a larger context, e.g. a Wizzard. This context has performed global initialization or updates and then selectively calls for rendering of a dispatcher.
clear
the form values are reset to empty (depending on
dtype
). Only fixed
values are not
changed.
the form is left with the intention to come back with new or changed values. The current form values are saved in the session object to be restored lated when we come back.
update
update the form after a dispatch.
The original form values are restored from the session object.
They can be overridden or completed by additional values provided
in the update
call.
The only anticipated event sequences are:
(new | edit) (clear | show | dispatch update)* leave?
Client__
the id of the form controlled by the dispatcher
The default is Client
.
ClientDescription__
the id of a method returning a dictionary or list that describes the form variables.
The default is ClientDescription
.
Each variable is described by a dictionary. The following keys are interpreted. There may be more, used for other purposes:
name
the variable name
init
an initial value for new
calls.
This is either None
or a value. None
means, use from the environment (if present). A missing
init
is equivalent to the type specific empty
value.
fixed
the value is not changed by clear
or
__call__
This is either None
or a value. None
means, use from the environment (if present).
If fixed
is not present, then clear
resets the variable to the type specific empty value.
permanent
the value is not changed by update
.
This should be a truth value, the default is 0
.
It is usually used together with fixed
variables to
prevent modification by update
.
It currently only affects update
. It might be more
intuitive, if permanent
would imply
fixed
.
dtype
the variables data type (used to determine empty values)
Must be either string
, int
,
list
or tuple
. Defaults to
string
.
SessionObject__
the id of the session object used to remember the values
The default is FSSession
.
It is expected, that the session object has get
and
set
methods to retrieve and set session data.
SessionKey__
the saved values are collected in a dictionary and saved under this key.
The default is the physical path of the dispatcher.
If the value is *dynamic*
, then the session key is
dynamically computed form the physical path. This is necessary, if
the dispatcher is used as part of a ZClass.
initializeSession__
the id of a method that initialized the session.
The default is initializeSession
.
FSSession
requires that the session is initialized
precisely once in each request that uses the session. Initializing
more than once may lead to loss of data. Not initializing may lead
to exceptions, let the application work with stale data and does
not save modifications. It is expected that
initializeSession
is idempotent, i.e. can be called
repeatedly in a single request without advertant effects.
For some session types (unlike FSSession), no explicit session
initialization may be required. In such a case,
initializeSession__
may be deleted.
new
fill a new form (mostly empty).
All variables get their initialization/fixed values (if
defined). Other variables get the dtype
specific empty
value.
The values are placed in REQUEST
and
REQUEST.form
.
None
values for init
or
fixed
are resolved from the environment.
The special value edit__=0
is defined.
The method is called either directly from the Web or from DTML, to better control the environment.
Arguments: DTML-like
edit
fill a form for editing (mostly filled).
All variables get their values from the environment with the
exception of fixed
variables. They get the specified
value, unless the value is None
.
The values are placed in REQUEST
and
REQUEST.form
.
The special value edit__=1
is defined.
The method is usually called from DTML which sets up the environment.
Arguments: DTML-like
update
update the remembered values and render the client.
The variables are filled with their remembered values. New
values from update
override pervious values, unless
errors__
has a true value. In this latter case, no
values are overridden. In no case, update
overrides a
variable declared as permanent
.
Usually, the update values are taken from the environment. If,
however, values__
is defined, then its value must be a
mapping and it, alone, is used for updating. The namespace is not
relevant in this case.
The values are placed in REQUEST
and
REQUEST.form
.
update
restores the base URL, remembered during the
last dispatch. This is in order to counter the lengthening URL
problem that is favoured by Zopes acquisition.
The method is usually called from DTML. It may, however, also be called directly from the Web.
update
accepts DTML-like arguments. However,
errors__
and values__
are treated
specially.
If errors__
is defined and has a true value, the
old values are simply restored. No values are overridden by the
update
.
If values__
is defined, then (with the exception of
errors__
), the environment is irrelevant. Only
values__
(which must be a mapping) defines values to
override remembered values. This provides for precise control over
the overridden values.
__call__
remember the current values in the session object (with the
exception of fixed
variables) and dispatch to a new
destination.
If the environment does not contain a value for a variable which
is not fixed
, then the empty value is used. This is
necessary for checkboxes and multiple selections to work
correctly.
The values and the base URL are saved in the session object for
later restoration by update
.
To determine the destination, __call__
looks for a
variable of the form (.*)__disp(.[xy])?
. It takes the
part match by (.*)
as the destination.
If the destination contains ?
, it is split at it.
The first part becomes the destination, the second part is decoded
as a query string and the corresponding parameters placed into
REQUEST
and REQUEST.form
.
The destination may be an URL path.
restrictedTraverse
is used to find the actual
destination.
If no destination can be found, the client is simply rendered
(equivalent to show
). This is useful to have shorter
URLs. Currently, the same happens, when REQUEST
does
not have a form
attribute. However, this may change in
the future.
The method is usually called only from the Web.
Arguments: dtml-like
clear
clear (make empty) non-fixed fields and render the client.
Arguments: DTML-like
show
render the client.
Arguments: DTML-like
getValues
return a mapping object containing the saved values.
This is the mapping saved in the session object. Writing to it changes the session maintained information.
Arguments: none
Most methods support DTML-like arguments. This means, there are
two optional positional arguments client
and
REQUEST
and arbitrary keyword arguments. Unlike
DTML-objects, the default value for client
is the
dispatcher object. REQUEST
may be a mapping or a DTML
namespace.
The methods construct a DTML namespace from this in the same
way, DTML objects do. When an object is rendered, the
render
method of this namespace is used.
Usually, new
, edit
,
clear
, and show
render the client. If,
however, DispatcherDoNotRender__
is true, rendering
and REQUEST
modification are suppressed. This allows
e.g. a Wizzard to call these methods just to change the remembered
values.
For a DTML object or when the object is not acquisition wrapped
or when the namespace is bound, the namespace's render
method is used for rendering. Other objects are rendered through
ZPublisher.mapply.mapply
.
Zopes acquisition and the possibility to call methods both via
HTTP and directly can lead to great confusion with respect to base
URLs. The base URL is essential for the resolution of any relative
URL in an HTML page. The Dispatcher tries to counter this confusion
by explicitly setting the HTML base element. For this purpose, it
must find out its own URL. Note, that it can not use
absolute_url
, as this method discards any context. For
new
, edit
, clear
,
show
and __call__
, the dispatcher assumes
that it was activated directly by HTTP and that it can use
REQUEST.URL1
or REQUEST.URL0
,
respectively. If this assumption is wrong, the caller can define
DispatcherURL__
. It should be the URL of the
dispatcher object. If the client is rendered at the end of an
update
, the dispatcher restores the remembered base
URL.
Note that the URL/BASE request variables are fixed for the rendering as well. They reflect the true client/destination information, not that of the dispatcher. Other request variables are not changed. This may change in the future.
Download the Dispatcher TGZ archive
and unpack it into your Zope Products
folder. Restart
Zope. You should then find a Form Dispatcher
entry in
your add-list.
This product is covered by a Python-like open source license. For details, see the Copyright notice at the top of Dispatcher.py.
render
. This allows to use Python Scripts with
namespace binding to be used as client and to pass parameters to it
via the namespace. Note, that this is not necessary in general, as
all dispatcher variables go through REQUEST
anyway.__call__
to behave like
show
, if no destination can be found.mapply
rendering is used for destinations which are
not DTML or unwrapped objects. This allows to pass parameters to
Python Scripts, even if they do not bind the namespace (which is
really dangerous), and to External Methods. A future implementation
should probably use the DTML render
, if the target
object uses namespace binding.