Users:
| BSAdv Home Page
| Release Notes
| Using BSAdv
| Youth Protection
| Installation
Developers:
| To Do List
| Database Tables
| Extending BSAdv
| Database Consistency
Extending BSAdv
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.
Files
BSAdv follows reasonably standard Joomla coding standards.
To add an element foo, the following files need to be created:
- 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/default.php - Turn the PHP data into HTML. Put JavaScript here to pass to the client, if you need. I found JSON an efficient way to transfer a PHP object or array to JavaScript, and back to PHP.
Additionally, I like to create the following:
- 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.
Development Process
To extend the functionality of BSAdv, you need skills in PHP, HTML, probably MySQL, and possibly JavaScript.
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.
JSON and JavaScript
Some of the more complex forms used in BSAdv interact with the user via JavaScript and DHTML.
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.
This allows a complex object to be transferred to JavaScript as one Javascript variable.
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.
- JavaScript, executing in the browser, writes the JSON string to a JavaScript string. It then executes eval() to turn the JSON string into a JavaScript object.
- Javascript, executing in the browser, creates one or more DOM objects, each of which appear as a separate web page to the user.
The general process is for the HTML to define one or more sections of the page with
<div>id="bsadv_name"</div>
constructs, where name is a named section of the page, of your choosing.
JavaScript then constructs one or more HTML representations for that section of the page and uses the construct
element.innerHTML = string
to write new HTML to that part of the page.
These page changes are normally done as a response to the user clicking a button on the screen, which executes one or more JavaScript functions, which creates a new 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.
For this to function, the designer must transmit all necessary database informatin to the browser, and the JavaScript must use it to create multiple HTML representations of that data, in response to user actions.
- Interacting with the user, JavaScript creates one or more variables, or modifies one or more variables from the server.
When the user completes the edits, he or she submits the data back to the server with an HTML
form action=
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.
The data has now completed the cycle from MySQL database, to Joomla server PHP, to browser JavaScript, back to the Joomla server PHP and back to the MySQL database.
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.
Some forms have simple HTML update variables and do not use DHTML or JavaScript.
DHTML and JavaScript are valuable when the application requires multiple display pages that change as a result of user interaction.
The event controller is a complex example of this.
Helper Controllers
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.
For example:
- To view account data on a single adult, use the URL
http://your_host_name/index.php?option=com_bsadv&controller=adults&target=adultaccounts
This calls the controller adults to select an adult.
It also passes the name of the eventual controller with the operand
target=adultaccounts
.
- After users select the adult, they are redirected to the target URL, with the id of the adult as an operand
http://your_host_name/index.php?option=com_bsadv&controller=adultaccounts&id=10
- 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.
- 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.
http://localhost/index.php?option=com_bsadv&controller=scout&edit=1&id=1&checkout_id=5
- 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'>
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.
- 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
site/views/static/tmpl/
Examples
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.
- scout - Uses JavaScript, DHTML, JSON and MySQL. Daunting.
- event - Uses quite a bit of JavaScript, DHTML, JSON and MySQL. Frightening.
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.
Sourceforge.net
Thanks to Sourceforge.net for hosting our project.