Conventions Install Learn Advanced Alphabetical
Fake FAQ TODO File List


The manual

This page assumes that correct installation of pabulumba has taken place. See Install for installation instructions.

1. Create an XML file

Let's assume you are the secretary of a local community group. The main activities centre around the monthly meeting, where the activities to be worked on in the next month are decided.

It's a monthly meeting that you want to record information about. Either create an empty file called "meeting.xml" using a text editor, or copy from (and then rename to "meeting.xml") any of the .xml files in the config folder of pabulumba - the latter is much faster.

This file will become an XML file. In an XML file, there are two main components: elements and attributes. Elements are identified by a start tag and a close tag (or the empty-element tag, e.g. <foo/>). Every single configuration file in pabulumba has a root document element called doc.


As on paper, the monthly meeting needs to be represented on a page with a heading.

	<page heading="Monthly Meeting permission="wrh"/>

There are now two elements visible on the page: the doc element (represented by a start tag and an end tag) and the <page element, which is nested inside the doc tags. The page element is also known as a self-closing tag. Both heading and permission are attributes, and they take just one text value, and cannot be nested, as elements can. The heading attribute should be self-explanatory. Let's worry about the permission attribute later (but if you really want to know, it limits the visibility of this page to users with various roles).

Also as on paper, information would be entered into a pre-designed form. A form element is required, and a form element requires at least one element element.

2. Create a single form element

	<page heading="Monthly meeting">
	<form name="meeting" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="max" useRules="n" previewColumns="~~" autoPreview="n">
		<element name="date_box" type="input" validate="date" label="Meeting date" mandatory="y" default="" maxSize="10" permission="whhhhhhhhh"/>

The above file will eventually result in a pabulumba web page which contains this:

The meaning of the many attributes on form and element should now become clear. Working from top to bottom in the image:

3. Validate the XML file, and generate the database entries

The form will not automatically be generated, nor will it be visible on any of pabulumba's menus. The database table and field/s have to be created first, and then "Meeting" needs to be accessed from a configuration file.

  1. Click the "Maintenance" button in the pabulumba main menu bar
  2. Click the "Validate XML config files and generate SQL" entry
  3. Use Ctrl-F, and search on the page for "meeting"
  4. Open a MySQL database command line window
  5. Cut and paste the line starting with "SET FOREIGN_KEY_CHECKS..." and ending with "SET FOREIGN_KEY_CHECKS = 1;" into the MySQL window
  6. Execute the SQL statements

4. Create the main menu entry

  1. Edit the file in the "config" folder called "main.xml", and insert a line as follows:
  2. <switch xml="meeting" xsl="pabulumba" action="display" permission="wrh">Meeting</switch>
  3. Save the "main.xml" file
  4. Click the "Main" button in the pabulumba main menu bar

5. Repeat steps 2-3 as often as necessary

Let's add in a text input box showing the location of the meeting. As in step 2, edit the "meeting.xml" file, but copy the only element line below itself.

In the new element, change:

  1. name to "location"
  2. validate to "sentence"
  3. label to "Location"
  4. default to "Public hall"
  5. maxSize to "45"
	<page heading="Monthly meeting">
	<form name="meeting" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="max" useRules="n" previewColumns="~~" autoPreview="n">
		<element name="date_box" type="input" validate="date" label="Date" mandatory="y" default="" maxSize="10" permission="whhhhhhhhh"/>
		<element name="location" type="input" validate="sentence" label="Location" mandatory="y" default="Public hall" maxSize="45" permission="whhhhhhhhh"/>

(And change label in the first element to just "Date" - everything on this page relates to meeting).

Click the "Validate XML config files and generate SQL" entry again.

Search for "meeting" again, and cut and paste the enlarged SQL code into the MySQL command window and run it.

Click the "New" button, and the following should appear:

Notice how the ID is "0" when a new record is created. The "XofXX" field displays "** new **", and the navigation and most other buttons are also disabled. The default value of "Public hall" is automatically inserted into the Location record.

If Save is clicked now, the error message will advise that "Mandatory field (Date) is currently empty". There are a couple of shortcuts to fix this, e.g. type:

On clicking "Save", the missing fields will be replaced with the current date's matching fields, or the alternative "00/00/0000", which is the date to use when a date is unknown as yet, and the field is compulsory.

6. Create a report menu entry

Copy the line created in the "config\main.php" called "reports.xml", and change the action attribute to "report" instead of "display":

<switch xml="meeting" xsl="pabulumba" action="report" permission="wrh">Meeting</switch>

Click on the main menu entry Reports; "Meeting" should now be visible.

Assuming that some entries have been created using the Meeting form, clicking on "Filter results using above criteria" will display the results in a tabular format. Because the "Meeting" form was created with an input box validated by "date", the reports page automatically generates two calendar boxes - a "From" and a "To" box, which can be used to filter (restrict or limit) the amount of output data. As different data types are added to the form, so will the "Reports" page for "Meeting" change.

The records can be exported directly into a popular spreadsheet format.

A very powerful (and hence dangerous) function of the "Reports" page is that it provides the ability to perform mass updates of data.

7. Create reference data

It will become clear that pabulumba uses itself to build elements that it then treats as building blocks. A good example of this is the SELECT LIST (or DROP DOWN LIST) or the radio button list. The options need to come from somewhere, and in pabulumba, there are two methods. The easiest method (but one which should be used with caution) is to simply list the options, separated with commas, in the XML config file against the attribute source:

<element name="meeting_type" type="radio" label="Meeting type" mandatory="n" source="Regular,Extraordinary" permission="whhhhhhhhh" javascript=""/>

The reason for caution using this method is that once these options are used in other records, their position should not be changed. In the above example, "Regular" will be stored as "#0", "Extraordinary" is stored as "#1". Spelling mistakes can be fixed, or another word substituted (perhaps "[No longer used]"), but the position's meaning should not be changed if it is required to be still used.

This radio button list (of two) can be turned into a select list by merely changing the type from "radio" to "select":

<element name="meeting_type" type="select" label="Meeting type" mandatory="n" source="Regular,Extraordinary" permission="whhhhhhhhh" javascript=""/>

The select list is still getting the reference data from the comma-separated list in the source attribute; it is just diplaying the options differently; there is still only a choice of one or the other.

Using a table to store reference data avoids the problem of predetermined positions in the comma-separated list. Simply copy a file similar to "config\animal_class.xml" naming it something relevant to the reference data, e.g. "meeting_type.xml". Replace the existing name attribute with "meeting_type" - this becomes the name of the MySQL table.

	<page heading="Meeting type" permission="whhhhh" />
	<form name="meeting_type" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="min" useRules="n" previewColumns="" autoPreview="n">
		<element name="label" type="input" validate="sentence" label="Meeting type name" default="" mandatory="y" maxSize="30" permission="whhhhhhhhh"/>
		<element name="deleted" type="checkbox" label="Deleted" mandatory="n" permission="whhhhhhhhh"/>

Validate the XML, and build the SQL query again, then run it in MySQL. Add the entry into "config\maintenance.xml" (the desirable location for files used in the creation of the other elements, especially those you don't want people playing around with).

Add the labels "Regular" and "Extraordinary" into the table.

The line that references this data in the "config\meeting.xml" file looks like this:

<element name="meeting_type" type="radio" label="Meeting type" mandatory="y" source="meeting_type" display="label" permission="whhhhhhhhh"/>

The source attribute here refers to the table of reference data. How does pubulumba tell the difference between a list of options and a table? Simply the presence of commas in the list; a table name can never have a comma in it.

The display attribute is both the name of the column in the database and the label in the configuration file which refers to the visible element of the option list. This name is not visible to the user of your application

There is a subtle difference in that radio buttons do not have an Optional option by default. At least one radio button must be chosen. Radio button options are also NOT sorted alphabetically as select lists are; this is to allow arbitrary orders similar to:

This radio button list was achieved using a list from within the source attribute itself, but the same effect could be achieved using a table as long as the names were entered in the order desired. However, the database may not always return records in id order, so if a strict order is required, use a select list instead of radio buttons. It can also then be decided whether an option must be chosen or not, by making the mandatory attribute either "y" or "n". A mandatory select list will contain a pseudo-option "Please select..." at the head of the options, whereas an optional select list will contain "Optional..."

Create a text area

<element name="correspondence" type="textarea" validate="sentence" label="Correspondence received" default="" rows="3" cols="80" keepHistory="n" showHistory="n" mandatory="n" maxSize="1000" permission="whhhhhhhhh"/>

If keepHistory and showHistory are both set to "y", a record of the changes made to this field can be maintained, and can be toggled visible/invisible by clicking the "+" and "-" icons.

Create a check box

<element name="apologies_read" type="checkbox" label="Apologies read" mandatory="y" permission="whhhhhhhhh"/>

Note that the asterisk indicating compulsory is just to draw the user's attention to it; a user cannot be forced to tick a checkbox.

Attach one or more files

<element name="file" type="file" validate="none" label="Correspondence " mandatory="n" maxSize="1000000" permission="whhhhhhhhh"/>

Click [Choose file] to select and upload a file. The file extension must be in the list of file extensions available in "Maintenance/File extensions"

Notice how files of the same name will be given an alias:

Attach one or more URL (link) entries

To add one or more URL entries, enter a URL into the input field and click "Save". "http" is not required; it is automatically added at the start of every URL. If this is not desired, edit the "pabuulumba.xsl" file and remove it.

<element name="url" type="url" validate="none" label="Useful URLs: " mandatory="n" maxSize="100" permission="whhhhhhhhh"/>

Attach a tree (hierarchical view)

A hierarchical view of data requires two references tables; one to store the definitions, and one to describe their relationship to each other.

1. Copy a file similar to "config\animal_class.xml" naming it something relevant to the reference data, e.g. "office_bearer.xml". Replace the existing name attribute with "office_bearer" - this becomes the name of the MySQL table. Add in the element with the name "root".

	<page heading="Office bearers" permission="whhhhh" />
	<form name="office_bearer" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="min" useRules="n" previewColumns="" autoPreview="n">
		<element name="label" type="input" validate="sentence" label="Office bearer title" default="" mandatory="y" maxSize="30" permission="whhhhhhhhh"/>
		<element name="root" type="checkbox" label="Is root element" mandatory="y" permission="whhhhhhhhh"/>
		<element name="deleted" type="checkbox" label="Deleted" mandatory="n" permission="whhhhhhhhh"/>

2. Validate the XML, and build the SQL query for "office_bearer", then run it in MySQL. Add the entry into "config\maintenance.xml".

3. Create a "root" entry (this will be invisible in the tree) and mark it as "Is Root Element", then enter the names of office bearers into pabulumba, e.g. add in President, Vice-President, Secretary, Treasurer, Chapter officers, Employees, Volunteers, Casuals, Interested parties. No other entries apart from "root" should indicated as "Is Root Element".

4. Create another XML configuration file (or copy "config/car_car") and make the following alterations. The name of this relationships file MUST be the name of the previously created file, then an underscore, then the name again, in this case "office_bearer_office_bearer":

	<page heading="Office bearer relationships" permission="wwwhhhhhhh" />
	<form name="office_bearer_office_bearer" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="min" >
		<element name="parent" type="select" validate="none" label="Parent official element" mandatory="y" maxSize="20" source="office_bearer" display="label" javascript="" permission="whhhhhhhhh"/>
		<element name="child" type="select" validate="none" label="Child official element" mandatory="y" maxSize="20" source="office_bearer" display="label" javascript="" permission="whhhhhhhhh"/>
		<element name="deleted" type="checkbox" label="Deleted" mandatory="y" default="0" permission="wwwhhhhhhh"/>

5. Validate the XML, and build the SQL query for "office_bearer_office_bearer", then run it in MySQL. Add the entry into "config\maintenance.xml".

6. Add the following line into "config/meeting.xml".

<element name="official_official" type="select" validate="tree" label="Presiding official " mandatory="y" source="office_bearer" display="label" permission="whhhhhhhhh"/>

If "Tree" is clicked, another window will appear showing the structure of the hypothetical community group. Clicking on the "+" icons will expand the tree; the "-" will collapse that level.

Clicking any of the labels will create a read-only option (and only one) inside the select box. If an input box (which can be modified) is desired instead, change the type to "input", add in a "maxSize attribute" with a value and run the validation/SQL again:

<element name="official_official" type="input" validate="tree" maxSize="50" label="Presiding official " mandatory="y" source="office_bearer" display="label" permission="whhhhhhhhh"/>

Create a one-to-many relationship

Real-world objects/scenarios are unlikely to be able to be represented with a simple list of data types. This simple list is represented by a form in pabulunba, with multiple records (all the same format) being created from the same template. The next step towards extending this functionality is adding multiple records on to a single form. A paper example would be an invoice, where one transaction will contain at least one item, but could potentially hold many. The common information would be stored on the "one" record, e.g. date, title of store, salesperson e.t.c., and a list of purchased items would be added as a table underneath.

To continue using the fictional commmunity group meeting, we will add a list of attendees to the meeting. Because the database cannot easily store a "one-to-many" relationship (represented in a diagram like this): ...

                     | ID:3      |
                     |           |
                     | Meeting 1 |
      |             |             |             |
+-----------+ +-----------+ +-----------+ +-----------+
| ID:1      | | ID:2      | | ID:3      | | ID:4      |
|           | |           | |           | |           |
| Person 1  | | Person 2  | | Person 3  | | Person 4  |
+-----------+ +-----------+ +-----------+ +-----------+

... it is required that we store the reference to the specific meeting with each individual attendee record:

+-----------+ +-----------+ +-----------+ +-----------+
| ID:1      | | ID:2      | | ID:3      | | ID:4      |
|           | |           | |           | |           |
| Meeting 1 | | Meeting 1 | | Meeting 1 | | Meeting 1 |
|           | |           | |           | |           |
| Person 1  | | Person 2  | | Person 3  | | Person 4  |
+-----------+ +-----------+ +-----------+ +-----------+

This sequence of records contains the minimum amount of information to link Persons 1-4 with Meeting 1.

Copy the "meeting_type" config table created in step 7 (Create reference data), and rename "meeting_type" to "attendee". This, by itself, would be sufficient to create a list of people's names (multiple records, each with a single name), but there would be nothing linking each name back to the meeting. To rectify this, identify a field in the "meeting" table which is likely to uniquely identify it - probably the "date_box".

(Any input field (such as the "date_box" in "meeting.xml") can be guaranteed to be unique if an attribute named "unique" (with a value of "y") is added to the element definition. MySQL will automatically validate the entry, and complain to pabulumba if it is already exists in another entry.)

Even though the field in "meeting.xml" is of type "input", it can be referenced in "attendees.xml" as a select list if the type is changed to "select". In order to make the date display correctly, the validate attribute should be set to "date".

<element name="meeting" type="select" validate="date" label="Meeting" mandatory="y" maxSize="20" source="meeting" display="date_box" javascript="" permission="whhhhhhhhh"/>

Validate "attendees.xml", and generate the SQL; run the SQL, and enter the names of several people against one or more of the meeting dates.

Note that the moment one field is entered into a grid, all fields are required. It is regarded that if the field is important enough to go n the screen, it should be mandatory. It is possible to leave the non-mandatory fields for their own form, which can be reached a single click of the GO button.

In order to add the "many" relationship, a grid reference must be created in the "meeting" config file:

<element name="attendees" type="grid" label="Attendees" autoRowNumber="6" source="attendee" selectCriteria="" filterColumn="meeting" mandatory="n" permission="whhhhhhhhhhh">
	<field name="label" maxSize="30"/>

This element is one of the few which contains another element; in this case, it has to hold at least one <field>. The value of "field" should be the name of the field to display from the "source". The width of this field can also be independently controlled by adding an attribute of "maxSize" with a value; this is useful if a number of text columns are required to fit into a reasonable area.

When "meeting" is next opened, it will display the grid entries recently created:

New attendees can be added by typing the name directly into the input box in the "Attendees" and clicking "Save". Text fields can also be edited directly by typing into the grid.

If the "Go" button is clicked, a filtered (limited) set of the attendees records will be available to view/change directly on the "attendees" form. Use the navigation records at the left to return to the "meeting" records.

Radio buttons elements cannot be added directly to the grid - instead they are converted to select lists, as are check boxes.

To delete a record from the grid, tick one or more of the checkboxes next to the "Go" button, and click "Save".

With grid data, you can put the most important information (and all the fields are compulsory) on the field list, and keep the others for the real form, where the rest of the fields can be filled out.


Input fields may have a wide variety of characters able to be entered, but only certain combinations of these may be acceptable to the form designer. Validation is the means whereby the data is checked against the acceptable criteria, or the form not accepted. All the following except for "selection" (used for type "select") may be used as possibilities for the attribute "validate".

Validation type Will accept
filename numbers, letters, full-stops, underscores, hyphens, or brackets
url input beginning with file:// or http://
email numbers, letters, full-stops, hyphens, semi-colons, or underscores
sentence characters found on a normal keyboard
integer positive or negative whole numbers
decimal numbers, the decimal point, or the negative sign
selection any selection from the select list
date Shortcuts: 't' => today, '1' => 1st of current month, year, '1/4' => 1/4 of current year
character any single character
none no validation necessary

Additional characters can be added into the "Sentence Pattern", which is a setting.


The buttons at the top of each page represent a main menu item, which comes from a config file called "menu.xml". Here are the default settings in this file:

		<menuItem xml="main" 		xsl="pabulumba" selectCriteria="" permission="wwwhhhhhhh">Main
		<menuItem xml="reports" 	xsl="pabulumba" selectCriteria="" permission="wwwhhhhhhh">Reports
		<menuItem xml="maintenance" 	xsl="pabulumba" selectCriteria="" permission="wwhhhhhhhh">Maintenance
		<menuItem xml="help" 		xsl="pabulumba" selectCriteria="" permission="wwwhhhhhhh">Help

Each <menuItem> is processed in order, and can use different XSL for each. The xml attribute points to a configuration file which must exist, or an error will appear (see Errors)


There is no such thing as an anonymous user in pabulumba. Someone without a username and password can view the login screen, but that is it. A default instance of pabulumba comes with a user with the name of "Albert Ross", and has a username of "username" and a password of "password". Each page/form change is checked against the access list.

Each new user requires an entry in the "maintenance/user" screen. A username, password, choice of system role (see Roles and permissions"), first and last name, and email address is all that is required.

Roles and permissions

Every user is allocated a role in pabulumba for the purposes of assigning the relevant level of security. These can be called whatever you like (the names of the default roles can be edited in "maintenance/roles"); the important concept to grasp is their relationship with permissions.

The permission attribute may have been noticed in the above examples, and will usually resemble "wwrhhhhhhh".

w: the permission to view and modify existing records, and create ("w"rite) new records
r: the permission to only view ("r"ead) records, and not modify them in any way
h: the permission which will remove visibility ("hidden") of a pabulumba element from a particular role

The position in the permission string represents the role of the user, specifically the "Permission value (position in permission attribute)". The value, any of "w", "r", or "h" determines what rights the users has to manipulate the elements in pabulumba.

The page permission attribute overrides all other permissions on the page


Setting labelExplanation
Date part display separatorA choice of date-part separators is available: either a "/" or a "-"
Date formatEither Day Month Year, or Month Day Year
File upload pathThe name of the folder where file uploads are stored. If changed, and files have already been uploaded to a different folder, they must be physically moved to the new location. This value should have a trailing forward-slash
On duplication, stay on current record or jump to duplicated recordIf [Duplicate] is clicked on a record, the option exists to stay on the current record, or jump to the new record
On duplication, copy historyIf [Duplicate] is clicked on a record, the option exists to copy all the associated history records to the new record
On duplication, copy filesIf [Duplicate] is clicked on a record, the option exists to copy all the uploaded files to the new record
On duplication, copy gridsIf [Duplicate] is clicked on a record, the option exists to copy all the related grid information to the new record
Record debug informationDisplay (and write to the log file) debugging information
Select filter thresholdSome select lists may have many options; more than can be feasibly scrolled through. The level can be set whereby if more records than this number exist, a filter box will appear that can restrict the options to those containing e.g. "ab"
Show deleted reference dataDeprecated
Sum prefixThe label at the bottom of a standard report where the column entries are summed
Count prefixThe label at the bottom of a standard report where the column entries are counted
Average prefixThe label at the bottom of a standard report where the column entries are averaged
Average precisionThe number of decimal places the averaged value displays
ERD canvas size (pixels)Experiment with this value to reduce the white space, or allow more room for the ERD on generation
Session timeout (minutes)he system will log a user out in this number of minutes if no action has been taken
Max length uploaded file nameAllow this number of characters in a file name
Config data sourceTest pabulumba using "file", then flip it across to "session" for greater speed AFTER running the Maintenance option "Import recently changed config files"
XSL template nameThe default XSL template name (no need for the ".xsl")
XSL sourceForce every form in pabulumba to use the XSL value in the previous setting, or use the named XSL template in the config file attribute. Useful to flip to "master" if there is an error in a customised XSL template.
Show navigation historyDisplay the box showing the last "x" forms visited
Max nav. history recordsSets "x" for the previous setting
Show record previewDisplays "x" customised entries in a box assisting with navigation
Max preview recordsSets "x" for the previous setting
Show page load timeDisplay how long the page took to generate
In Test modeUse Test mode to inhibit real emails being sent when configuring new forms, and forward to the Test email address instead
Test email addressThe email address used in conjunction with the previous setting
FROM email addressThe email address displayed as "From" on receipt by users
Use rulesTurn the use of rules on/off globally. Useful for checking functionality without being restricted by having to change roles where otherwise required
LanguageThe language that messages are displayed in
Sentence patternAugment the regular expression string with characters not normally found on a US keyboard
Encrypt password (MD5)Choose between using plain text passwords (recoverable with access to the database), or 1-way encrypting a nominated password (MD5)


Report filters are automatically generated from config files. Any radio button, checkbox, or select list becomes a dropdown with their normal options as well as "No filter" (the default). Date fields are turned into two fields so a range of dates can be entered (from / to), or only one can be used keeping the other open-ended. Text fields can be restricted to specific content with either matching entries or using wildcards, i.e. "f%" will match "fiddle" and "folderol" ("fo" followed by any number of characters); "f_n" will match "fin" or "fun", but not "fiddle".

To show the non-filtered (or filtered, if the options have changed) results, click the [Filter results using above criteria] button.

Clicking on [Pass all results to print report] will send the results into an XSL template of the user's own design. This may seem complicated initially, but as long as integral elements are left in the template, a basic knowledge of HTML manipulation should be all that's necessary to craft an elegant report. Clicking the name of the form after the text "Return to report: [xxxxx] will take the user back to the report generation page.

[Pass selected results to print report] will use the same template, but provides the ability to pick and choose records with the checkboxes at the left.

Click [Clear filter and results] to start a new search for results.

Click [Export all records...] to download results in a spreadsheet format.

If a particular result set has been found, but some of the details are incorrect, they may be able to be updated in bulk. Select the records to be changed using the checkboxes at the left, change the filter to the values those records should have (note that text fields searched for with wildcards will need exact values or none at all on updating in bulk) and click [Update selected records using above criteria].

All records in the output can be selected/deselected using the buttons at the bottom of the displayed records.

Discuss aggregateOn and aggregateFunctions

A report can be exported to either a DIF file or an Excel file. The choice can be made by setting the "fileType" attribute of a form, with the options being either "dif" or "xls". If "fileType" is set to anything other than "dif" or "xls", it will default to "dif". Please note that there is also a difference as to how the data is presented; this will depend on whether grids are used or not. There is no easy way to represent a split cell in a .dif file, and so grid information (potentially multiple records) is represented on the single line that represents the record's ID. Each row is surrounded by square brackets, and each field is separated with a pipe ("|"). The number of rows will match the number of records for the form.

The "xls" format produces potentially more than one row per record for the form (technically the cartesian product of the "one" and the "many" tables). An example may serve best to represent the difference between the "dif" and "xls" formats. Assume a very simple form with just a person's name and a single grid with three columns. Assuming the first form record shows a label and a grid with three rows, and the second form record shows a label and a grid with two rows, this would be represented in the two different formats as follows:

Name Grid: Street Grid: Town Grid: Postcode
Albert Ross 23 Gulliver Way Melbourne 3000
Albert Ross PO Box 127 Sydney 2001
Albert Ross 1 Waynard Crt Newcastle 2024
Laurie Keats 12 Pinetree Cres Darwin 4000
Laurie Keats 33 Brindlewood St Perth 5000

The "xls" format allocates individual cells to all data, including the repeating information from the main record. This format should be used when specific values are required from the grids, such as the landline and the mobile phone numbers () for the one person (the main record). The number of records can get very big quickly, due to the requirement to repeat the common information.

Name Grid [Street | Town | Postcode]
Albert Ross [23 Gulliver Way | Melbourne | 3000][PO Box 127 | Sydney | 2001][1 Waynard Crt | Newcastle | 2024]
Laurie Keats [12 Pinetree Cres | Darwin | 4000][33 Brindlewood St | Perth | 5000]

The "dif" format more closely represents the on-screen output, and accurately represents the main form record count.

Custom reports

If a user is competent at writing SQL (using MySQL syntax), pabulumba provides the ability to run ad hoc queries which can be far more flexible than using the standard report interface. The standard reports will only generate data from one base form (database table), albeit with all lookup information attached.

Using custom reports, any combination of the tables (including system tables) can be effected. For example, the "log" table does not have a form for it (although one could easily be created). It might be easier to write a query that answers the relevant questions (and might also limit the results).


SELECT * FROM log INNER JOIN user ON log.user = INNER JOIN action ON log.action_id = ORDER BY DESC LIMIT 30

It must be pointed out that using "SELECT *" with a target table to jump into introduces complexity, as pabulumba requires injection into the SQL statement to obtain the id of the record(s) required. pabulumba will handle all SQL queries which contain joins or derived tables, but nothing more complex. If the user finds the query is limited to results from the target table alone, the query should be modified to extract all required fields by name.

Custom XSL

The default XSL templates which come with the basic installation show all elements (within each form) underneath the preceding one. The order is determined by the order in the XML config file. This output may be acceptable for data input, and viewing individual records on-screen, but even the standard reports do not provide output which is suitable for printing or distribution to a client. This is where the real power of XSLT is introduced.

IMPORTANT: ensure a backup copy of pabulumba.xsl exists (or at last resort, access to

If you would prefer a different background colour, change the XSL file.

If you only need several of the elements on the page displayed, modify the XSL so it only display the selected element. This style of manipulation is what directs appropriate output for a small mobile device as an alternative to a regular sized screen.

Send emails automatically

An email can be sent from a record automatically with the new updated content.

<form name="user" showId="y" showNavButtons="y" showSaveButton="y" showNewButton="y" showDeleteButton="y" showDuplicateButton="y" showXofXX="y" initialId="max" sendEmailOnSave="user,1">

The values here are the table to use the value from, and the number of the email template. The body of the email template is set in "config/email_template" and the values of the fields can be referenced by inserting the name of the element (db field name) within braces, i.e. "{fullname}"

Create rules

There are five types of rule which can be applied to a form element:

  1. Apply Permission to Target element when trigger element value equals Current for Role(s)
  2. Apply Permission to Target switch when trigger element value equals Current for Role(s)
  3. Apply SQL/RegExp for Role(s)
  4. Apply SQL/RegExp when Element value attempts change from Current to Proposed for Role(s)
  5. Restrict Element options to Current and Proposed when Select element value == Current for Role(s)
  6. Apply Permission to Target as switch when Element value == Current for Role(s)

Use Rule Type #1 when the permission attribute for an element on the page has to change as the result of a drop down list being a certain value. For example, if a field "description" cannot change (i.e. be read-only) when the "status" is "Proposed" and the user is "User", then:

Why would you use this rule, and why can't it be accomplished using the permission string values against the element alone? The permission strings are always in effect for an element, no matter what the value of other fields are. Rules give the developer the ability to make a permission override when another element (in this case, a select box) is a certain value. If a permission is usually read-only for a certain role, it could be used to make the permission writeable for one state only. The opposite might be similarly useful, allowing write access for the role except when the select list has a certain state.

Rule Type #2 is very similar to #1; it just operates on a switch on the page instead of an element. Use Rule Type #2 when the permission attribute for a switch on the page has to change as the result of a drop down list being a certain value. For example, if a switch is required to be read-only under all circumstances unless when the "status" is "Proposed" and the user is "User", then:

Use Rule Type #3 to restrict the options in a select list to those listed in the from and to values. This is used to set up transitions which can only be performed by certain roles, for example, a regular user could change an order status from "Proposed" to "Entered", but only a supervisor role would have a rule set to allow moving that order status from "Entered" to "Approved" or maybe back to "Proposed" again.

Use Rule Type #5 to run either an SQL statement/query or check the contents of an input field with a regular expression. Note that any SQL query could potentially change many records; this should be tested outside pabulumba first ensuring it has the desired effect.

There are a couple of macros which make text substitutions: [CURRENT_ID], [CURRENT_VALUE], and [PROPOSED_VALUE:xxxx]. The first, if placed in the SQL query text, will be replaced with the ID of the current record. The second, [CURRENT_VALUE] will be replaced by the value held in the database for the trigger element name. The third, [PROPOSED_VALUE:xxxx], will accept any of the names of the form elements in place of the "xxxx", and will replace the macro with their proposed value. Note that this value may be the same as the current value if it has not been changed. If a particular field was read-only or hidden, then the PROPOSED_VALUE:xxxx could also represent the current value of any field, as it could not have been changed by the current user. The functionality may exist in the future to extract the current value of all fields, not just the trigger element, without resorting to this method of getting a proposed value from a field that cannot change.

SQL validation is not as efficient as using regular expressions, but may be more familiar to the average user. Where the option "Validating SQL" is used, it means "use an SQL statement to look for something that shouldn't exist in a field value, and if it exists, complain with an error message." An example of this would be where an "f" is undesirable in a field value. The rule would be set up as follows: select '%f%' from [PROPOSED_VALUE:xxxx]

There must only be one possibly repeating SQL condition; the logic quickly becomes rather tortuous if more than one one-to-many relationship is referred to here, especially if there are differing numbers of each, as would usually be the case.

Remember that rules only apply for the role of the current user; if the rule is supposed to run for more than one specific role, it must be added in twice. (Having one rule run for all roles is a proposed future enhancement.)

Validating SQL requires that an empty set is returned from the SQL query; if anything is returned, then the rule will not allow the current record to save.

The first two rules apply on displaying a record, and the other three rules apply when saving is about to take place.

Note that any SQL command which attempts to update the current form and current record will be immediately changed by the value in the field itself, if entered. The sequence of actions is 1) check and implement rules, 2) update the current record.

The contents of the reason field will be displayed when an UPDATE command as the proof that it has run successfully.

There is likely to be a performance hit if using SQL to validate contents of fields because a database connection is required to be opened; it would not be particularly noticeable, but using regular expressions is preferred, as they are much more powerful and faster. However, a regular expression cannot update field values, so if it is necessary to use, use SQL.

SQL: if any SQL query returns a value, this is regarded as FALSE, and will return the error,and display the Reason. Therefore, the SQL statement should try and find something which is not supposed to be there, so if it returns a result, it throws the error, displaying the reason. Although negative logic would be more correct, this may be slightly easier to understand. The SQL is applied for a certain role, so ensure the Allowed roles table is completed accurately.

This screen is multi-use, so there are a few fields which are required to be completed to satisfy teh validation, rather than be used for that particular rule.

SQLText2 is only used for checking in the grid values.



At present, pabulumba speaks three languages: English, French, and German. As most text is user-controllable, there are not many system-generated messages, but all of these are translated, and available from the "config/message".

Apologies to the non-English speakers, but there are still a few validation messages which have not been translated as they incorporate system variables, so are more difficult. This should be remedied shortly, however.


Multiple different types of searches can be set up, using an SQL query as the basic parameters. Complicated search scenarios can be set up, but only one table can be the target of the search once results are found.


A list of the most recently navigated-to items can be displayed at the left of the main form area.


A preview of whatever the user would like to see can be displayed at the right of the main form area.


User-generated processes can be added to add customised functionality to records and recordsets.

Error messages

The most commmon error message seen by users would be this one:

Warning: DOMDocument::load(): I/O warning : failed to load external entity "file:///C:/Apache24/htdocs/pabulumba/config/DOES_NOT_EXIST.xml" in C:\Apache24\htdocs\pabulumba\pabulumba.php on line 4828

This appears because the configuration file does not exist. A change has been made in any of the menu configuration files which is attempting to point to a file which does not exist. This might be a typo (in which case the solution is to fix the typo in the menu file), or a completely missing file.

Unknown column 'file_url' in 'field list' [ERR050 - select meeting_type,file_url from meeting ]

Warning: DOMDocument::load(): Premature end of data in tag doc line 1 in file:///C:/Apache24/htdocs/pabulumba/config/project_status.xml, line: 8 in C:\Apache24\htdocs\pabulumba\pabulumba.php on line 4661

This appears because of a mismatched <doc> tag in the XML document. Warning: DOMDocument::load(): expected '>' in file:///C:/Apache24/htdocs/pabulumba/config/demo.xml, line: 33 in C:\Apache24\htdocs\pabulumba\pabulumba.php on line 5061 This appears because of a --> left in a config file. Note how it tells you the line number to look for the problem.