============
Control Flow
============

:Revision: $Id: control_flow.txt 30439 2005-12-08 20:29:58Z dkuhlman $

.. sectnum::    :depth: 4
.. contents::   :depth: 4


**Warning:** This document is not up to date.  Many details are
wrong.


This document describes the "flow" in the NuxCPS3Document for the
complicated cases, namely data retrieval, document rendering and
data editing. It describes it step by step as it happens, in
the following order:

1. Retrieving the data

2. Displaying a form with the data

3. Saving the updated data

To make it all somewhat clear (or maybe not) there is the
associated ``control_flow.dia`` document that outlines what's in
here graphically, but in much less detail.


Introduction
============

Each document will have an associated portal_type, defined in the
portal_types tool. The type defined will probably be defined by a
new type of portal type (instead of like Factory Type
Information). The type definition is referred to throughout this
document as a template.


Retrieving the data
===================

The document's data is accessed through a DataModel object. This
object is created by calling the document's ``makeDataModel()``
method (This is actually currently done by the Template, but when
document-specific schemas are implemented, it will move to the
Document). This method creates a DataModel object by fetching all
the schemas that are valid for the document and adding them to the
DataModel. The schemas can be either local to the document, local
to the template, or some sort of global schemas (the exact way of
setting up the global schemas have yet to be determined).

A schema is a collection of fields, and the DataModel is basically
a temporary collection of schemas, specific for each document.
Each schema also has it's own storage settings, that determine
where the data for the fields are to be stored. This could be an
SQL database, or object properties, or something else. The data is
accessed through StorageAdapters which are created by
StorageAdapterFactories. Each schema has it's own
StorageAdapterFactory with it's own settings.

One StorageAdapter is created for each schema and kept in the
DataModel for access to the data. Each StorageAdapter is also
called upon to fetch the data. The data is also stored in the
DataModel as a data cache so that the external storage isn't
called upon each time you make a change.

The ``makeDataModel()`` method then returns the new DataModel
object.


Data access
-----------

You can access the data in the DataModel in two ways. First, the
DataModel has a dictionary type interface, so to get the data for
a field you just access the DataModel with ``datamodel['fieldname']``
and the data will be returned. You can also create DataStructures.
A DataStructure is a dictionary-type object that is especially
designed for usage with forms. It keeps the data rendered into a
format that is directly displayable, i.e. a text string (or
possibly a number). This is used when rendering documents.

(And it just struck me that if we are to have different format of
one field in different Layouts, we need to call the FieldWidget to
render, which means another refactoring...)


Displaying a form with the data
===============================

Displaying a document is done by calling the document's
``render()`` method, with a parameter naming the Layout to be used
when rendering.  Layouts are collections of FieldWidget; each
FieldWidget has a corresponding Field that the widget is
responsible for rendering.

The document fetches the Layout in question, either locally, if
allowed, or from the template, which in turn gets it locally or
from the global storage.  The document then creates a DataModel
(see above) and calls the DataModels makeDataStructure method to
create a DataStructure that is then passed to the Layout's
``render()`` method.

The Layout will then in turn go through each FieldWidget, pick out
the relevant data from the DataStructure and call each
FieldWidget's ``render()`` method with that data, and with the
layouts Renderer.

A Renderer is an object that knows how to render basic graphical
elements, such as bits of text, and editboxes. The FieldWidget in
turn knows which of these graphical elements it needs in order to
render the field. A text field will either be rendered as a string
or as an editbox, and the FieldWidget know which, while the
renderer in turn knows how to create strings and editboxes. It's
important to note here that different layouts may render the same
field differently. For example most documents will have both view
and edit layouts, one for viewing the document and one for editing
it, where the view layout will render almost everything as text,
while the edit layout will render everything as HTML fields.

Each Layout will have it's own renderer, depending on which target
the layout is created for. There may be a CmfRenderer that uses
METAL macros defined in portal_skins to render, and a HtmlRenderer
to render into pure HTML, and a PDF renderer to render to
PDF-files, and TextRenderer to render into pure text (useful if
you want to send document as e-mail, for example) and a
StructuredText renderer to make the whole document into a STX
file, etc.

So the Layout calls ``render()`` on each FieldWidget who in turn
calls the methods it needs on the Renderer, such as ``text()`` and
``editbox()``. The Renderer returns a text-string that represents
the rendering, which is concatenated together, and
``Layout.render()`` finally returns the full rendition for
display.


Saving the update data
======================

The procedure outlined in the previous section is exactly the same
no matter whether it is a form or just an HTML page, or for that
matter a PDF file. Assuming that it is a form used for updating
the document's data, this is the procedure to update the data from
this form.

When a document is updated, a DataStructure needs to be updated
from the REQUEST object. The DataStructure could be created at
this point, but to improve performance it may be beneficial to
store the DataStructure as well as the DataModel created when the
document form was rendered in a volatile attribute on the
document.

The DataStructure will go through it's fields to see if they exist
in the REQUEST and update it's data accordingly. It also keeps
track of which fields have been changed. After the update, the
document passes the updated DataStructure to the DataModel's
commitDataStructure method.

CommitDataStructure first validates the data in the DataStructure
by calling the fields and validating the data with them. If all
Fields validate properly, it updates it's internal storage of
data. It uses the DataStructure's modified flags to keep track of
which schemas that have been affected by modified data. It then
calls it's own ``_commitData`` method to commit the data for
storage for each affected schema. It does this by using the
``writeData()`` method on the StorageAdapter connected to that
Schema.

Thats it, I think. Hope this helps.

