version: #1 (current)  |  last edited by: Mike Ho  |  on: thursday, november 3, 2005, 11:00 am pst (about 13 years ago)


This article will get you started with understanding the entire Qforms architecture, which is the presentation layer for Qcodo, offering an object-oriented, stateful, event-driven architecture for display logic and presentation.  It will step you through a simple Calculator sample application, which will utilize some basic Qform controls.



NOTE: This article covers Beta 1 of the framework.  If you want documentation for Beta 2, please check out the <a href=“http://examples.qcodo.com/” class=“link_body”>Examples Site</a>.


While a lot of hoopla surrounds Qcodo and its features in <a href=“/documentation/article.php/2” class=“link_body”>code generation</a>, there is a whole other half to Qcodo that is just as instrumental to true rapid application development.  And that other half is Qforms.

Qforms is an object-oriented, stateful, event-driven architecture for forms rendering and handling.

Now, that is definitely a mouthful, so let's break that down a little.

Basically, the Qforms is the presentation layer (which includes display logic) for Qcodo.  Now, the first thing to note is that you don't always have to use Qforms for each page in your web application.  And in fact, there are many pages which are better off not using Qforms.  A perfect example is this page you are reading right now on this Qcodo.com website.  Even though it's a database-driven web page (the text of the article, itself, comes from the database), there is minimal display logic.  Therefore, it makes more sense to output this not utilizing Qforms.

As the name suggests, for the most part Qforms is much better suited to help with the handling of web pages that deal with form data.  It is object-oriented, meaning it is able to treat each HTML “widget” as an object (which is called a Qform control).  Your basic Qform controls include your standard HTML form elements, like textbox, “select” listbox, checkbox, button, image button, radio, and file.  But multiple HTML components and elements can be combined to make much more complex objects, like date/time pickers and datagrids (which is the foundation for all the various generated “list” pages, like the “List All People” page, the “List All Issues” page, etc.).

Note that last item: datagrids and “list” pages.  Looking at a “list” page, it doesn't look like it's a form.  But remember that Qforms is also stateful and event-driven.  A list page definitely has state (the data in the datagrid, itself, as well as the current preferences for which column to sort by, and if pagination is enabled, which page you're looking at).  And that list page definitely is event-driven.  Clicking on a page number or a column heading (to change sort preferences) triggers an event to have the datagrid pull and display the data differently.

So yes, there will definitely be pages where you won't want to use Qforms.  But there will also be many pages that don't necessarily “look” like a form, but could take great advantage of Qform's architecture through both the included Qform controls as well as custom controls.

Calculator

In order to get a better understanding of the architecture, we're going to focus this article on purely the Qforms side of the architecture, meaning no code generation, and no database.

Let's create a simple four-function calculator as a form, where we basically just have two textboxes, and a listbox that allows us to select an operation, and a button to perform the action.  And lastly, the let's display the output as HTML, and let's be sure to keep the values of the textbox and selected listbox item, essentially maintaining some sort of state on the page.

In regular PHP, we would begin to do the dreaded spaghetti code (code where a lot of PHP and HTML are intertwined together in one code base) to get this done:

calc_1.php &nbsp; (<a href=“/sample/calculator/calc_1.php” class=“link” target=“_blank”>Run</a>)

<include>/sample/calculator/calc_1.php</include>

That looks simple and straightforward enough.  A lot of the embedded PHP code within the HTML is there mostly to support the ability for the form to “remember” and redisplay the values that were entered in prior to submittal (which is essentially giving the form “state”).

Let's take a look how the same functionality could be achieved with Qforms:

<code_split_left>
calc_qform_1.php &nbsp; (<a href=“/sample/calculator/calc_qform_1.php” class=“link” target=“_blank”>Run</a>)

<code_split>
<include>/sample/calculator/calc_qform_1.php</include>
</code_split>
<code_split_middle>
calc_qform_1.php.inc

<code_split>
<include>/sample/calculator/calc_qform_1.php.inc</include>
</code_split>
<code_split_right>

Yikes!  Qforms made the calculator form require more code!  From a Lines of Code perspective, the straight-up PHP way looks by a better deal.  However, note that this calculator has very little functionality right now.  Our next step will be adding some validation and simple “business rules” that every calculator should have.  But also, even though Qforms requires more code, you can hopefully see that there is a distinct separation of the display logic from the presentation layer.

calc_qform_1.php is just pure PHP.  But the included HTML template file, calc_qform_1.php.inc, is almost pure HTML, with the exception of just a few “render” calls to your Qform objects.  This separation of HTML and PHP is at the core of Qform's ability to try and minimize spaghetti coding.

If you look at the HTML template file, you'll also note that the HTML &lt;form&gt; tags are never used.  Instead, the form object, itself, will render those tags via RenderBegin and RenderEnd.  This is necessary to allow the Qform framework to manage state.

Notice that calc_qform_1.php simply defines a Calculator Form object.  Within that object, it declares several Qform controls (2 textboxes, a listbox, a button, and a label).

For each Qform control, it is constructed using “new”.  Every Qform control requires the first parameter to be the Parent Form object (in almost all cases, that would be “$this”).  The second parameter is the optional ControlId parameter (the ControlId is what gets rendered as, for example, &lt;input type=“textbox” id=“controlIdHere” name=“controlIdHere”&gt;).  Although it's rarely used, you do have the option of explicitly setting the a Control's ControlId to be a specific value.  Usually, you can simply leave it blank and Qform will automatically generate a ControlId of “controlX”, where X is a unique number.

The form also defines two methods that are event handlers, a “Form Create” event handler and a “btnCalculate Clicked” event handler.

And finally, the last line actually kicks off the Form's execution though the static “Run” method.  The method's first parameter is the name of the form, itself, you are trying to run.  The second parameter is the filename of the to-be-included HTML template file.  This parameter is actually optional.  By default, it will append “.inc” to the current PHP script's filename, and use that as the filename of the HTML template include file.  However, you can override this default by explicitly entering a filepath to the include file you wish to use.

Event Handling for Forms and Controls

Our calculator form has two event handlers.  The “Form Create” event handler is tied to the form's “Create” action in line 11.  The “btnCalculate Clicked” event handler is tied to the btnCalculate's “Server” action in line 26.

Every Qform control is capable of having a “Server” and/or “Client” action defined.  For buttons, the action is obviously triggered when the button is clicked.  For textboxes or listboxes, it's triggered when the value is changed.

“Client” actions are pure Javascript (the event handling stays on the client-side).  “Server” actions are a PHP method that you define (“btnCalculate_Click” in our example).  If you define both a client and a server action, the client action is run first and then the server action.

(Note that with Beta 2, we will be introducing a third action, “Asynchronous” actions, which will allow you to write PHP code to handle AJAX functionality).

The way Server Actions operate is that a trigger will cause the form to post back to itself, which means that the Form will be run “again”.  In our example, the form will recognize that the btnCalculate button was clicked, and therefore it will execute the specified “btnCalculate_Click” method that we defined.

While all Qform control objects support this ServerAction and ClientAction behavior, events for the Form object, itself, is more complicated.

Forms can have the following actions declared:

  • Run
  • Load
  • Create
  • PreRender
  • Exit


In order to discuss these five event handlers, let's first understand the process flow for Qform Form objects in general.

How Form Objects Process

The form follows the following process flow in order:

<ol>* The first thing the Form object does is internally determine if we are viewing this page fresh (e.g. not via a post back) or if we have actually posted back (e.g. via a control's triggered ServerAction).

  • If it is posted back, then it will retrieve the form's state from the FormState, which is a hidden form variable containing the serialized data for the actual Form instance.  It will then go through all the controls and update their values according to the user-entered data submitted via the post, itself.
  • Next, regardless if we're post back or not, the Run action (if defined) will be triggered.  Again, this will be run regardless if we're viewing the page fresh or if we've re-posted back to the page.
  • Next, if we are viewing the page fresh (e.g. not via a post back), the CreateAction (if defined) will be run (CreateAction is typically where you would define and instantiate your various Qform controls).  Otherwise, the LoadAction (if defined) will be run.
  • Next, if we're posted back because of a ServerAction that points to a specific PHP method, that PHP method will be run.  In our case, if we clicked on btnCalculate, “btnCalculate_Click” will be executed for this step.<br> <br> Qforms also offers a robust validation system (which we will show off in a sec).  If the Control that triggers the ServerAction has its CausesValidation property set to “true”, then before executing the ServerAction, the Form will go through every visible control in the +entire +Form and call Validate().  Only after ensuring that +every +control is valid, will the Form go ahead and execute the assigned ServerAction.  Otherwise, every Control that its Validate() fail will have its ValidationError property aggregated with the appropriate error message.<br> <br> By default, Buttons (including ImageButtons and LinkButtons) have CausesValidation set to “true”.  All other controls have CausesValidation set to “false”.
  • If defined, the PreRenderAction will then be run.
  • The HTML include template file is included (to render out the HTML).  The RenderBegin() and RenderEnd() methods must be called within the template in order to output the appropriate FORM tags, but also to output any additional functional HTML, JavaScript and hidden form elements to allow the Qform object to work correctly.  (Qcodo will in fact throw an exception if either RenderBegin and Render End are not called).
  • And finally, the ExitAction (if defined) is run after the HTML has been completely outputted.
    </ol>

At any point, if a Form event handler is not defined, the Form will simply not trigger that event, and move on.

So that should hopefully give you a broad overview of how the Form, itself, works.  As you can see, our first cut as the Calculator form barely scratches the surface of the deep functionality that Qform has to offer.

Now that you have a rough idea as to how Qforms works, we encourage you to check out <a href=“/documentation/article.php/4” class=“link_body”>Adding Functionality to Qforms</a>.



Copyright © 2005 - 2019, Quasidea Development, LLC
This open-source framework for PHP is released under the terms of The MIT License.