| BSAdv Home Page
| Release Notes
| Using BSAdv
| Youth Protection
| To Do List
| Database Tables
| Extending BSAdv
| Database Consistency
Extending the code refers to adding compatible MVC elements, without changing the existing code, and without changing the flow of code in existing MVC elements. This is distinctly different than bug fixes or enhancements of existing code. To begin, study the organization of data in the database tables.
Decide if you need to create a report or a form. Reports read data from the MySQL database and create representations in HTML or other formats. Forms interact with the user and can modify the data in the database. Forms are generally more difficult to write than reports. Determine what data you need from the MySQL database, and how you want to represent it to the user.
BSAdv follows reasonably standard Joomla coding standards.
To add an element foo, the following files need to be created:
Additionally, I like to create the following:
- site/controllers/foo.php - Pretty standard Joomla stuff, but you can implement unusual program flow here. I use it during development to execute site/views/foo/tmpl/update.php, displaying the database update commands without actually updating the database.
- site/models/foo.php - Read and write the MySQL database. Create PHP data structures that are convenient for the view.
- site/views/foo/view.html.php - This is pretty simple. I use this to pass PHP variables to the template. You could do more here, if you want.
- site/views/foo/tmpl/debug.php - While developing the model, change the controller to execute this instead of site/views/foo/tmpl/default.php. Simple print_r statements in this file let you see the data that you are creating. After you get the data correct, change the controller back to execute default.php and create the HTML output with that file. It is convenient during development to have this file available, if you are concerned about the data being returned by the model.
- site/views/foo/tmpl/update.php - Similarly, when creating model code to update the database, it is convenient to actually display the MySQL UPDATE commands. Change the controller update function to execute this file instead of actually executing the model update function. That way, instead of having to decipher MySQL errors, you can see the offending commands directly. After the MySQL commands look good, change the controller to execute the model update function, which may implement most of the code that you debugged in this update.php file.
If you have a preferred method to develop Joomla code, have fun! If you want some hints, this is the way I would go about it.
- Create the model. Create files:
- site/controllers/foo.php - Temporarily have the display function execute the debug template:
JRequest::setVar( 'layout', 'debug' );
- site/views/foo/view.html.php - This is real simple. Just pass the variables from the model to the template.
- site/views/foo/tmpl/debug.php - Pretty simple, just put print_r within <pre> and </pre>, as many as you want.
- site/models/foo.php - This is where most of your work will occur. While you perfect this file, look at the resulting data structures from the print_r commands in debug.php.
Iterate, making changes to site/models/foo.php until you like the variables displayed by site/views/foo/tmpl/debug.php.
- Create the template. Create file: site/views/foo/tmpl/default.php -
Change the controller to execute this instead of debug.php:
JRequest::setVar( 'layout', $task );
If this is all that you want your extension to do, you are done.
- If you want your extension to return data to the MySQL database, you need to implement the following:
- Create site/views/foo/tmpl/update.php - Code here takes data returned from the client and creates MySQL update commands to be reviewed by the developer.
- Add an update function to the controller. Temporarily have it execute update.php by using
JRequest::setVar( 'layout', 'update' );
Use this combination to debug the code in update.php. Iterate on this until you like the resulting SQL code.
- When the resulting MySQL database commands from update.php look good, add an update function to the model. Most of this code will be a copy of the code you debugged in update.php. Change the controller to
JRequest::setVar( 'layout', $task );
- Do lots and lots of testing.
This concept needs a little more explaination here. This is the flow of data:
- The model reads selected data from several MySQL tables and creates one or more PHP objects.
The organization of the objects depends on how the data ultimately needs to be accessed in the browser.
- The view passes the PHP objects directly to the template.
- The template executes the PHP function, json_encode(), converting each PHP object into a JSON-encoded string.
It may be more compatible with Joomla to convert the PHP object to JSON in the view, then have the template just pass it to the browser, but I chose to do it this way.
The general process is for the HTML to define one or more sections of the page with
constructs, where name is a named section of the page, of your choosing.
element.innerHTML = string
to write new HTML to that part of the page.
This appears to create a completely new page, but in reality, just updates the HTML on a part of the page.
This it the DYNAMIC part of DHTML and is a powerful way to decrease response time to the user.
When the user completes the edits, he or she submits the data back to the server with an HTML
usually as a result of selecting a Submit button.
For convenience, we often encode the return data as a JSON string.
To simplify determining what changes have been made to the variable(s), we keep an unmodified version of the data and transmit it back to the server along with the edited version.
This reduces problems that occur when multiple edits are occuring simultaneously in the database.
- The server receives both the modified and original JSON strings, decodes them both into PHP objects, compares the modified PHP object to the original object, then creates database update commands to make the required database changes, if required.
It is quite a path, but JSON helps keep complex data in an object form throughout the process from server to browser and back to server.
Not all BSAdv elements use DHTML.
Reports create HTML output only and do not perform database updates.
The event controller is a complex example of this.
Several controllers are useful only to help other controlers.
- adults: Provides a list of all adults for the user to select. This is called by any controller that uses data from one adult only. The URL for the target controller is passed to this controller. When the user selects an adult, Joomla is redirected to the target URL, with the adult id appended. In this way, each controller does not need to manage the adult selection. It can use this controller to select the adult. The user has a consistent interface to select adults, and code duplication is minimized.
- To view account data on a single adult, use the URL
This calls the controller adults to select an adult.
It also passes the name of the eventual controller with the operand
- After users select the adult, they are redirected to the target URL, with the id of the adult as an operand
- checkout: Provides an interface for the user to view the names of other users that may be simultaneously editing the database. This can reduce the chance of multiple users making incompatible edits to the database. This is a complex sequence of events.
Note that it is allowed for multiple users to edit the database, even the same table, at the same time.
It is unlikely, but possible that problems can occur when multiple users are entering dulicate information on the same event, or if multiple users are editing the same existing data.
BSAdv has been designed to avoid the possibility of data corruption.
Corruption should not occur, but it is possible in some cases, that some new data may be ignored, or new changes ignored.
See the section on Database Consistency.
- The user selects a link to edit data. The form has the following action:
<form id="bsadv_form" method="post" action="/index.php?option=com_bsadv&controller=checkout" name="bsadv_form">
and passes two hidden variables to the checkout controller. The first tells checkout which database table(s) are being edited.
Multiple tables are designated by a colon-delimited list.
<input type=hidden name='checkout' id='checkout' value='scouts'>
The other hidden variable tells the checkout controller where to go after checking out the table(s).
This is almost always the controler that edits the table(s).
<input type=hidden name='redirect' id='redirect' value='index.php?option=com_bsadv&controller=scout&edit=1&id=1'>
- The checkout controller shows the user all of the registered edit sessions.
At this point, the user may decide not to proceed with edits.
The checkout controller form has the following action:
<form method="post" action="index.php?option=com_bsadv&controller=checkout&task=update">
and passes two hidden variables to the update function of the checkout controller. The first passes the target URL that was passed to the checkout controller:
<input type="hidden" value="index.php?option=com_bsadv&controller=scout&edit=1&id=1" name="redirect"/>
The second passes the table(s) that need to be checked out.
<input type="hidden" value="scouts" name="tables"/>
The update function creates a new row in the checkout table, then redirects to the URL passed to it.
The id of the new row in the checkout table is sent to the edit session.
This is used later, during the checkin step, to delete the row in the checkout table that was created for this edit.
- To increase resistance to hacking, the checkout controller creates a random number. This is stored in the checkout table and is passed to the editing controller, and to the edit window in the browser. This number is submitted by the browser to the server along with edited data, and is required to match before any update to the database can occur.
- The user ends up in an edit state, with the table(s) that are being edited entered in a new row the checkout table. At this point, other users can see that this user is editing the database, and which tables are being edited.
- The update function of the edit controller does two things: it usually updates the data, and it removes the row in the checkout table. The update function of the controller calls the checkin function in the model. The checkin function first checks that the random number from the edit session matches the number in the checkout table. If it matches, the update function removes the row in the checkout table that corresponds to the checkout_id, then updates the data in the database.
<input type=hidden name='checkout_id' id='checkout_id' value='5'>
<input type=hidden name='code' id='code' value='5555'>
The update function of the edit controller also takes the URL passed to it and redirects the user to it. This is usually the view session of the data just edited.
<input type=hidden name='redirect' id='redirect' value='/index.php?option=com_bsadv&controller=scout&id=1'>
- events: Similar to adults, and provides a method for the user to select an event prior to executing a controller for that event.
- scouts: Similar to adults, and provides a method for the user to select a Scout prior to executing a controller for that Scout.
- static: Provides the overhead to display a static HTML page, one with no database access or programmable components. Each page is located in a separate file in
Look at the following BSAdv code for examples of the previous explanations.
The code can be found in the distribution tar file.
The files are distributed throughout directories under the site directory, including site/controllers/, site/models/ and site/views/.
See the examples for foo (above) for their locations.
Output only (reports)
Takes data from the MySQL database and creates HTML
- bsadv - Reads one MySQL table. Pretty simple.
- roster - Reads several tables and creates a composite PHP data structure. Educational.
Output and Update (forms)
Takes data from the MySQL database and creates HTML forms, which the user can modify.
Submitting the form returns data to the server, which is used to potentially update data in the database.
- scoutdeeds - Uses simple forms and creates MySQL commands. Reasonable.
Use in units other than Boy Scout Troops in the USA
Plans exist for converting BSAdv for use by Cub Scouts and other types of groups. The first step is to separate the advancement and merit badge databases from the BSAdv software. This will allow them to be updated separately. Next, the Cub Scout (or other group) advancement data needs to be mapped to the Boy Scout tables, and parallel update paths defined for the Cub Scout advancement updates. The different terminology used in the web pages for Cub Scouts will be implemented with translation files. Stay tuned. This will be interesting.
If the existing table structure cannot adequately represent the advancement requirements of your unit, then the tables would need to be modified. In addition to adding or deleting fields and tables, it may be necessary to modify the software.
Thanks to Sourceforge.net for hosting our project.