VMOSS Calendar Example
VMOSS (Volunteer Management Open Source Software) is currently under development as a standalone implementation of the Sahana Volunteer Management module.
Contents |
Code Structure
VMOSS uses the same file structure as Sahana. The majority of the files located in the /mod/vm directory.
Architecture
VMOSS uses a Model-View-Controller (MVC) architecture to manage the interaction between the user and the system. According to this design pattern, the system's data (the model) is separated from the user interface (the view), so that these two aspects of the system can be dealt with independently. Changes to the data will not affect the user interface and vice versa. Interaction between the model and view is managed by the controller, which contains the program's control logic.
UML
The following UML diagram gives a detailed break-down of the design, including the function names and attributes currently implemented in VMOSSDemo.
Data Scmema
The following diagram shows how VM module interacts with the Sahana framework.
Documentation
VMOSS Documentation hosted on Sourceforge
VMOSS Exercise
Problem Statement. Add a new menu named Calendar to the VMOSS menu that when selected brings up page containing a simple appointment form that includes two fields, appointment name and date. When submitted the appointment is added to an appointment table in the database and the returned page displays an updated list of appointments in a table format.
Design. We will create a new entity in VMOSS for the calendar, which means that create calendar subclasses of the model, view, and controller.
Procedure
1. In PhpMyAdmin, make database changes so that the access controller recognizes the new page.
INSERT INTO vm_access_request (request_id, act, vm_action, description) VALUES (101, 'calendar', 'display_appointments', 'Display Calendar - Show Appointments'); INSERT INTO vm_access_request_role (fk_access_request, fk_role) VALUES (101, 0), (101, 1), (101, 2), (101, 3), (101, 4);
2. In PhpMyAdmin, create a table on the VMOSS database to store all appointments:
CREATE TABLE vm_appointment ( id INTEGER(11) AUTO_INCREMENT, name VARCHAR(255), date DATE, PRIMARY KEY(id) );
3. Create a function in the DAO to retrieve all appointments called getAppointments(), and return an array of arrays. Each array in this list would have entries from id, name, and date.
function getAppointments() { $result = $this->execute("SELECT id, name, date FROM vm_appointment"); $appointments = array(); while(!$result->EOF) { $appointments[] = $result->fields; $result->moveNext(); } return $appointments; }
Create another function in the DAO to add an appointment called addAppointment($name, $date).
function addAppointment($name, $date) { $this->execute("INSERT INTO vm_appointment (name, date) VALUES ('$name', '$date')"); }
4. In Eclipse, create a template file called 'display_appointments.tpl' in a new calendar directory in the templates directory. This template can expect to get a array of appointment information to display. It should also output the form to add a new appointment. In order to use one page for both input and outpu, we use a hidden form element add_appointment and value 'Y'.
<h2>Appointments</h2> {php} shn_form_fopen('calendar&vm_action=display_appointments'); shn_form_fsopen('Add Appointment'); shn_form_hidden(array('add_appointment' => 'Y')); shn_form_text('Name', 'name'); shn_form_date('Date', 'date'); shn_form_fsclose(); shn_form_submit("Submit"); shn_form_fclose(); {/php} <table border="0"> <thead> <tr> <td>Name</td> <td>Date</td> </tr> </thead> <tbody> {foreach $appointments as $app} <tr> <td>{$app.name}</td> <td>{$app.date}</td> </tr> {/foreach} </tbody> </table>
5. Create a CalendarView class that extends the main View class. This class contains a single function called displayAppointments($appointments), which would expect an array of arrays that is returned from the DAO::getAppointments() function. This function should assign the result to the templating engine and display the template. Put this class definition in a file called 'CalendarView.php' under the 'view' directory.
class CalendarView extends View { function displayAppointments($appointments) { $this->engine->assign('appointments', $appointments); $this->engine->display('calendar/display_appointments.tpl'); } }
6. Create a CalendarController class that extends CalendarView and implements the Controller interface.
- It needs one function called controlHandler($getvars). Within this function, we can switch($getvars['vm_action']) and add a case for 'display_appointments'. For the code, if $getvars['add_appointment'] == 'Y' then we process the addition of an appointment by passing the name and date to the DAO::addAppointment function. No matter what, we call displayAppointments($dao->getAppointments) (which is legal since the controller is a subclass of the view) to show all appointments.
Put this class definition in a file called 'CalendarController.php' under the 'controller' directory.
class CalendarController extends CalendarView implements Controller { function controlHandler($getvars) { global $dao, $global; //first authorize the user $ac = new AccessController($getvars); if(!$ac->isAuthorized()) return; switch($getvars['vm_action']) { case 'display_appointments': if($getvars['add_appointment'] == 'Y') { echo 'hello'; $dao->addAppointment($getvars['name'], $getvars['date']); } $this->displayAppointments($dao->getAppointments()); break; } } }
7. Modify shn_vm_default() in main.inc to dispatch control to the CalendarController if a match for $getvars['act'] == 'project' is not found.
else if ($_GET['act' =='calendar'){ $controller =new CalendarController(); $controller->controlHandler($_REQUEST);' } else...
In main.inc add the include statatement for the Calender Controller.
require_once('controller/CalendarController.php');
8. Finally, in the menu.inc file, in the shn_vm_mainmenu() function, add the following line to display the menu item for the appointment form (add before the menu is closed;):
$ac->addMenuItem('Calendar', $ac->buildURLParams('calendar', 'display_appointments'));
To simplify the procedure somewhat, this example avoids creating a calendar model class.