The Form-Class Design Guideline

To state the obvious, forms must be visually manifest as HTML and submissions to them must be processed and responded to. Some websites make a total mess of the browser address bar by having form submissions make HTTP GET requests to the server. Others keep the address bar clean by using HTTP POST requests. Either way the submitted data is processed by a form handler on the server that is expecting the form. Exactly which form handler (or parts of a general form handler) will actually run, is determined by the server on the basis of the URL to which the form is submitted. This URL will be that given in the form HTML, either in the form action button or for the form as a whole.

With Dissemino matters are more formal. Firstly, all form submissions use HTTP POST. Secondly, since the point of hierarchical data classes is to capture descriptions of real world objects, and the point of forms is to create and edit such objects, it follows that forms should be closely matched to a data class. Ideally, a form submission would only create or edit a single object of the applicable data class, and its subclass objects. This ideal is known as the form-class design guideline.

It is OK for forms to have fields that are unrelated to data class members, e.g. verification codes. It is also OK to use multiple forms to create or edit data objects with a large number of members. As long as submissions do not create or edit more than a single object (subclass objects notwithstanding), then the form is within the guideline. It is however a guideline, not a golden rule. There may be circumstances where it would make sense to ignore the guideline, but it is not something that should be done without a very good reason.

In the configs, assuming guideline adherence, forms are usually assigned a data class. This avoids the need for the data class to be specified, in both the form fields and the form handler steps. If the data class is not set in the form, it can be set in the form handler. Shorthand however, was not the objective. A more important consequence of the form-class guideline, is that the data classes directly imply forms and thus form handlers. As stated the introduction, the web engine uses data class definitions, to create default forms and form handlers. These are crude devices, with basic form HTML, basic form validation JavaScript, and no functionality beyond creating and editing data objects. You don't have to use them but they are a good starting point and an effective aid to rapid webapp development.

Form Virtualization

Dissemino forms are virtual, only becoming manifest when a form definition is referenced. The relationship betweem form definitions and form references is similar to, but not quite the same as that between data classes and data objects. There are three form related entities to consider: Form definitions; Form references; and Form handlers; These work together as follows:-

Form definition Determines what the form will look like in terms of fields, form action buttons and supportive HTML. It states which form handler will be invoked in the case of each form action button (there must be at least one). The definition can states the data class, but it not state either the repository or the data class context (see note).
Form references These are the points of use so they state the repository used in submissions and the class context. The references also generate the form HTML.
Form handlers These process the submissions using the class stated in form defintion and the repositories and class context stated in the form reference.

To be clear the class context (introduced in "ID Allocation", article 2.3 "Datum and Data Objects in an Application"), is simply the use of different ids for the same data class in order to state how it is deployed - either as native or as a sub-class. It is specified textually as either a pure class name or of the form "class_name.member_name". Class context does not detract the three form entities from doing as their names suggest. A form once defined, however it is subsequently referenced will always appear the same and have the same buttons which will POST the form data through to the same form handlers.

Respectively, the three form entities are manifest internally as C++ class instances of hdsFormdef, hdsFormref and hdsFormhdl, created during the config read process in response to <xformDef>, <xformRef> and <xformHdl> tags. There is only one minor departure from this theme. The <xformDef> tag can either be in-situ (within a page), or be independent. Because it is the hdsFormref that generates the HTML an in-situ <xformDef> tag creates both a hdsFormdef and a hdsFormref.

This demarcation sometimes raises eyebrows. It is tempting to think that as the form definitions contain everything needed to generate form HTML, the task of so doing ought to fall to the hdsFormdef class. Instead hdsFormref generates the HTML in spite of not holding any of the form details itself and needing a pointer back to the applicable hdsFormdef to get this information. The form definitions are essentially inert. They state much but do little. Form virtualization separates the abstract from the real. The relationship between form definitions and for references is a akin to that between a class and an instance of the class. The former is theory, the latter is fact.

Form virtualization makes no practical difference in the very common case where a form is defined within the only page that will display it. In earlier versions of Dissemino, forms had to be defined in-situ. There were no hdsFormdef or hdsFormref, only a form class (hdsForm) created in response to an <xform> tag - which both defined the form and generated the HTML. The Forms worked but with an earlier and inferior database regime. There was a 1:1 relationship beween data classes and repositories and sub-class objects were always held in a separate repository. The single object container hdbObject was likewise so there had to be an instance for each sub-class object. Articles did not support forms lest this lead to illegally nested <form> tags in the generated HTML.

Numerous cases arose in which form definitions were being repeated with only minor differences, leading to confusion and error. Several factors pointed to form virtualization. What actually forced the issue however, was the introduction of the data class default forms and form handlers. As these defaults are generated directly from the data class definitions, and not within any page or article, form references were needed to import the defaults into pages and articles. This necessitated HTML generation by form reference, as otherwise no HTML for the defaults would ever appear. From this point on, it made no sense for there to be two different approachs to form HTML generation so the regime was rationalized so that in all cases, the HTML would be generated by form references.

Form Management

In Dissemino, forms are managed by maps in the hdsApp (HadronZoo Dissemino Application) class, mirroring the approach of the HDB which manages data object model entities in maps in the hdbADP (Application Delta Profile) class. One such map is hdsApp::m_FormDefs, a 1:1 map between form definition names and form definitions. Upon encountering an <xformDef> tag, the config read process (assuming the proposed name does not yet exist), creates a hdsFormdef and adds it to m_FormDefs. <xformDef> has only two sub-tags of significance, <xfield> to add fields and <xformBut> to add form action buttons. All other <xformDef> sub-tags serve only to define the supportive HTML. Each form action button in the form definition must name a form handler. The form handler itself will be defined later since in the configs, form definitions must always precede form handler definitions. Form handler names are added to another hdsApp 1:1 map, m_FormHdls.

Form references, regardless of whether they are generated by an <xformDef> or a <xformRef> tag, use three hdsMaps namely;

m_FormUrl2Hdl1:1 Form action URLs to form handlers (used to invoke form handlers)
m_FormUrl2Ref1:1 Form action URLs to form references (used to obtain form handler op context)
m_FormRef2Url1:many Form reference pointers to form action URLs (used by hdsButton::Generate())

Note that ULRs are required to be unique only in so far as there must be a separate URL for every combination of form handler and class context incident in the configs. Where there are two or more form references to the same form definition and using the same class context, the URLs can be different but there is no need for them to be.

Form Operation

Consider the statement in the opening paragraph, "Exactly which form handler (or parts of a general form handler) will actually run, is determined by the server on the basis of the URL to which the form is submitted. This being that given in the form HTML, either in the tag of the form action button or in the tag for the form as a whole". To be more specific, there is no general form handler in Dissemino and URL first identifies the form reference, not the form handler. All form submissions are by POST and none by GET. All HTTP requests are handled by hdsApp::ProcHTTP(). This uses the URL to look up the form reference in hdsApp::m_FormUrl2Ref and the handler name in hdsApp::m_FormUrl2Hdl. The handler name is then used to look up the form handler in hdsApp::m_FormHdls. The function hdsApp::ProcForm() is then called with both form reference and handler. It is this function that executes the form handler which comprises a series of Dissemino executive commands (instances of hdsExec).

In order for form submissions to invoke the correct form handler in the correct class context, the generated form HTML must have the correct URL for the form reference. This can be in the <form> tag itself or in the <input> tag of the applicable form action button. Page/article HTML generation is a matter of iterating the array of visual entities (hdsVE derivatives), for the page/article and calling the Generate function on each one. The visual entities equate to HTML tags and each implements Generate in accordance with its own requirements. The array is only the top level of visual entities in the page/article. Where these have sub-tags, Generate will recurse.

In this process, hdsFormref which produces the <form> tag, is just another visual entity. That hdsFormref::Generate only has the visual entities for the form body by means of a pointer back to the hdsFormdef is an aside. The thing to note is that the all important URL isn't going to be anywhere among them. Nor is the URL stored elsewhere in hdsFormref, only the class context is. Whether the URL is vested with the form or the button will depend on the configs but both hdsFormref::Generate and hdsButton::Generate must be capable of producing the URL. In either case the URL is looked up in the 1:many hdsApp map m_FormRef2Url using the pointer to the hdsFormref as key. The m_FormRef2Url map is 1:many because a form can have multiple form handlers and it is not compulsory for multiple form references to the same form definition in the same class context, to always use the same URLs.