B-Forms Design Factors
Before I started web developement using PHP, I have done a lot of commercial development using Oracle Forms, and Oracle Forms is where I have got my inspiration for this library. However, while developing it, I have adopted the concept to the environment of the web and PHP. Since the library has gone through several major revisions, I left things that work and are useful, and removed things that did not work or that I never used, resulting in a tight but powerful library, following these design factors:
No unneeded inheritance. In the first version of the library, I defined forms by inheriting from the base class. I found that defining a new class every time is really boring and does not add any value. Then I thought of Oracle Forms, and implemented an architecture where you define the form structure out of the boilerplate classes, and then add the behaviour of the form by defining triggers.
Minimum of explicit operations. It is always annoying to tell every object in the script what it should do in very detailed way. To avoid it, I have set up a system of meaningful defaults, so that most of the time the default operation of the library will suit your needs. In addition, instead of explicitly setting the triggers for the form, you just need to name them properly, like, for example, form_on_open(), and they will be automatically called. If you define nothing, nothing will be called.
Block architecture. This is another feature inspired by Oracle Forms. Blocks are essentially tables, where you can store several objects with the same properties. Blocks allow you to create forms for compound objects. For example, a weekly time report form will contain at least two blocks: one for the actual report object (a single row block), and one for the project records, containing hours spent by the day of the week. This second block may contain several records at the same time, since one could work on several projects in parallel.
Orthodox Oracle Forms architects would usually add a third block for control elements such as buttons. I generally just put buttons on the data blocks where they make more sense, especially since I have not yet implemented the equivalent of base-table blocks - blocks that automatically load the data from the associated SQL tables.
POST-process-redirect. Through trial and error I have found that to avoid defining the same form in more than one place, it is more convenient to generate and process the form by the same script. It also has the added value of re-displaying the form once again, if the data submitted by the user does not pass the validation criteria. As a result, each form is submitted to the same page that generated it. After your script successfully processes the results, e.g. saves the submitted data, it should redirect the browser to the target location and exit.
Manual or automated form generation. Most of the times forms have standard layouts. To simplify coding for this majority of cases, I have created two layouts:
BaseLayout, which is a form, where each field with its label takes a separate row in a two-column table, and
TableLayout, which is designed for multi-row blocks, and represents a table with header row of labels, and then a row of entry fields for each row on the block.
The actual HTML generated by these layouts can be easily customized, although most of the time it is enough to play with the provided CSS stylesheet.
However, when you need a special layout, in which you are trying to position fields in a less regular manner (for example, trying to fit as many fields in each row as possible - to compress the length of the page and make as many fields visible at once as possible) - then you would have to do manual form layout, writing your own HTML and calling two library functions field() and label(), which will generate the code for labels and fields of your form.