Tuesday, May 4, 2010

Usecase scenario near completion

I am very happy to announce the Kukuicup-Drupal is almost completed with its Usecase scenario phase. Participants can now view all open activities once they logon and navigate themselves to the "Activities" subtab in the "Myenergy" tab.












User can submit his activity once clicking on the "Submit for Verification" link. This will take him to the activity node itself that was created earlier by an administrator of the system. The activity node would look like the image below.














This is an example of a textfile verification type. The node will display a textfield for the user to submit his answer, and it will also display a larger textarea so that he can input additional comments if he has any. Clicking on the submit button will then submit the answer that will be stored in the database. The screen after the user has clicked on Submit would like like this:
















The administrator of the system can create and monitor the activities as wells as approval/disapproval of the answers submitted by the participants. The administrator can create a new activity by clicking on the Admin tab.
















Clicking on "Here" would take the administrator to the "Create Activity Node" page, which needless to say allows him to create a new activity. An administrator can also view answers submitted through clicking on the "Activity Manager" subtab under the Admin tab.















Here, the administrator can either Award or Decline a user submitted answer. Awarding an answer will take that entry and transfer it into the completed verifications table below. Administrator can also decide to "Undo Decision" which will take the entry back to the pending verifications table.

There are a few more tasks in which we have to complete before finishing our Usecase scenario. One such tasks would include automating the publishing of the Activity Nodes once the publication date has been reached. We hope to complete these tasks and move onto the next steps before the end of the semester.

Tuesday, April 27, 2010

Enable Ajax Mode in Drupal

I have been trying to work with Ajax in Drupal and I must say it was a cumbersome experience. First of all, even though I could find some online example (source codes), most of them were sort of advanced intermediate level codes and they were really difficult to understand what was actually going on. Moreover, the example codes I based off of never really worked without having to tweak them a little. I found that there was lack of good example Ajax code for Drupal; hence, I decided to provide my solution (that worked) here.

First of all you will need to define what you want in your forms. Basically with Ajax, you would want something that dynamically changes the contents of your form without having to reload the entire page. In my example, I placed a checkbox which will, after it's been clicked, display additional fields titled 'question' and 'answer'.

Here is basically what you will need to add in your hook_form function:

function activitymanager_form(&$node, $form_state) {
function activitymanager_form(&$node, $form_state) {


$form['textfield'] = array(
'#type' => 'checkbox',
'#title' => t('Textfield'),
'#default_value' => $form_state['values']['textfield'],
'#ahah' => array(
'path' => 'activitymanager/autotextfields/callback',
'wrapper' => 'textfields',
'effect' => 'fade',
)
);

$form['textfields'] = array(
'#title' => t("Generated text fields for the verification types"),
'#prefix' => '
"textfields">',
'#suffix' => '
'
,
'#type' => 'fieldset',
);

if ($form_state['values']['textfield']) {
$form['textfields']['question'] = array(
'#type' => 'textfield',
'#title' => t('Activity Question'),
);
$form['textfields']['answer'] = array(
'#type' => 'textfield',
'#title' => t('Activity Answer'),
);
}
return $form;

}

The Textfield form displays the checkbox itself. The '#ahah' field defines the Ajax behavior. '#path' directory should map to your callback function, which will be called everytime a user clicks on the checkbox. In my case, the callback function is called activitymanager_autoindex_callback. Therefore, the path to the function should be 'activitymanager/autoindex/callback. You must also set the path to your callback function in your hook_menu function as follows:

define(TEST_PATH,'activitymanager/autotextfields');


function activitymanager_menu() {

$items = array();

// Setup the initial menu option.
// yoursite/?q=test
// if you use clear URLs
// yoursite/test
$items['test'] = array(
'title' => 'Test setup',
'description' => 'A simple test form.',
'page callback' => 'drupal_get_form',
'page arguments' => array ('activitymanager_form'),
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM
);

/**
* This is the path in your site to the ajax/ahah callback function.
*/
$items[TEST_PATH] = array(
'title' => 'Test setup',
'description' => 'A simple test AHAH callback.',
'page callback' => 'drupal_get_form',
'page arguments' => array (
// first argument is the callback function.
'activitymanager_autotextfields_callback'),
//'test_ahah_cb'),
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM
);

return $items;
}
The above code is necessary to tell Drupal how it can find the callback function. It is quite cumbersome to add a new entry here everytime you create a new callback function, but it is a necessary step.

Finally here is my callback function:

function activitymanager_autotextfields_callback() {

// Get form from cache.
$form_state = array('storage' => NULL, 'submitted' => NULL);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);

$args = $form['#parameters'];
$form_id = array_shift($args);
$form_state['post'] = $form['#post'] = $_POST;
$form['#programmed'] = $form['#redirect'] = FALSE;

drupal_process_form($form_id, $form, $form_state);
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);

$textfields = $form['textfields'];
$output = drupal_render($textfields);

// Final rendering callback.
print drupal_json(array('status' => TRUE, 'data' => $output));
exit();
}
there were some things in this code that I had to tweak to get it to work properly. When I first ran this code, Drupal would for some reason submit the form whenever I clicked on the checkbox without notifying me of it. So if I clicked on the checkbox 5 times, I would end up with 5 duplicate entries in the database. This is obviously not what I wanted, so I began researching what was actually happening. I found out soon that the drupal_process_form function inside my callback function is causing the above behavior. I am yet to understand why Drupal decides to submit the form here, luckily though I figured out a way to work around this issue. I found that the some of the values in $form_state array can be used to change the behavior of drupal_process_form function. I inserted the following code just above my call to drupal_process_form fucntion:
$form_state['rebuild'] = 'notempty';
This eliminated the submit problem I was having. My callback function now looks like this:

function activitymanager_autotextfields_callback() {

// Get form from cache.
$form_state = array('storage' => NULL, 'submitted' => NULL);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);

$args = $form['#parameters'];
$form_id = array_shift($args);
$form_state['post'] = $form['#post'] = $_POST;
$form['#programmed'] = $form['#redirect'] = FALSE;
$form_state['rebuild'] = 'notempty';

drupal_process_form($form_id, $form, $form_state);
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);

$textfields = $form['textfields'];
$output = drupal_render($textfields);

// Final rendering callback.
print drupal_json(array('status' => TRUE, 'data' => $output));
exit();
}
I hope that somebody in the future finds this posting helpful, as adding an Ajax function in Drupal was not an easy task (at least for me).

Tuesday, April 20, 2010

Problem with Drupal Coding Standards?

If you are just starting to learn Drupal modules, and you are also new to PHP, it might be a good idea for you to brush up on Drupal Coding Standards. I know this sounds kind of boring, but it is a good practice. It is also very important if you intend to share your module with others in the future. This practice will make your code a lot easier to read for others who may wish to modify your module.

Drupal Coding Standards, as you might be able to guess, is basically similar to PHP coding standards. There are, however, some that are very specific to Drupal modules. The coding standards are explained here:

http://drupal.org/coding-standards

I will explain some of these listed above in detail.

Two spaces for indentation is implemented in Drupal standards. No white spaces should follow the end of the line. All line should end with a '\n' character. As opposed to '\r\n' for carriage return and line feed implemented widely in Windows system.

For all the $form[] = array(...); statements, you should format the lines so that it is easier to read. Following is an example from our Activity Manager module.

$form['activitytype'] = array(
'#type' => 'radios',
'#title' => t('Activity Type'),
'#required' => 'FALSE',
'#options' => array('Activity' => t('Activity'), 'Event' => t('Event')),
'#description' => t("Select type of event"),
'#default_value' => isset($node->activitytype) ? $node->activitytype : '',
'#weight' => -4
);

Notice that each element of the array is separated by a new line, while a comma is inserted right before the '\n' character. Also on the following line:

'#default_value' => isset($node->activitytype) ? $node->activitytype : '',

It is important to note that a space should be inserted before and after the '?' character (which denotes 'then'). This is also true for statements like:

$string = 'Hello' . 'World';

where a space should be inserted before and after the '.' which denotes concatenation.

For long lines that span beyond 80 characters should be formatted with new lines to make them easier to read. For instance in our Activity Manager module:

$additions = db_fetch_object(db_query('SELECT activitytitle, activitytype,'
. ' activitystartdate, activityduration, activitypublicationdate,'
. ' activityexpirationdate, activitykukuinuts, activitydescription,'
. ' activityverificationtype FROM {activity_manager} WHERE vid = %d',
$node->vid));

The code above is a good example of a line of code which could have easily gone beyond 80 characters. We managed to resolve this problem by ending the long string with a single quote, adding a new line and concatenating the next piece of line using the same method. The code provided above is a result of the repetition of the steps described here.

Drupal Coding Standards may seem a little annoying at first, but it is actually a good practice that everybody should follow if you are thinking about creating and sharing your own custom module. I would also suggest that you do this early. Learning about the coding standards after writing 2000 lines of code seems that it could be more than a annoyance.

Tuesday, April 13, 2010

Creating a Drupal Module

Creating a Drupal Module is not an easy task. In my last blog entry, I introduced a method in which to create a very simple Drupal Module. We are now doing something more complicated than a "simple Drupal Module", and I would have to say that initially, it was not a pleasant experience.

As I mentioned before, Drupal needs at least 3 files to run. The .info, install, and the .module files. While most of the important stuff is in the .module file, the three files are almost equally important. The .install file takes care of the database setup. It is basically run only once during the installation of the module. The .module file does almost everything else.

Drupal has an interesting way of handling custom modules. It does so by providing us with _hook functions which we are free to modify. At the same time, however, we are restricted only to modify these _hook functions. It is therefore, important that you first sit and learn what each of these _hook functions are for and how are you supposed to modify them.

Sometimes making more than a module to achieve a task becomes necessary in Drupal. For our case, we have developed an activity module, which handles the creation of activities. We also developed another module called signup that works together with the activity module to enable people to sign up for an activity.















There are also different types of modules in Drupal. The above example "activity manager" that we developed is a node module. As the name suggests, this module creates new nodes and interacts with the database fairly frequently.













The above image demonstrates how a user can fill out all the fields in Activity module to create a node. Each of the field above is a php form in the _form hook function. Once the user clicks on the submit button, the module sends the necessary data to the database to create your new node.














Here is how we made our Signup module. It essentially lists out the activity/events and provides a button for you to be able to signup for them. Unlike the activity module, this module does not produce any nodes. Once the user clicks on one of the sing up buttons, the module first retrieves the necessary information, user name, from the user and saves those information in its own table in the database. This way the module can keep in track of who is signed up for what activity. Also the module allows one person to sign up for more than an activity.

Tuesday, April 6, 2010

Creating a Custom Drupal Module

I had a little practice learning how to create a custom module for Drupal CMS this week, and I would like to take this opportunity to share this experience with the rest of the world.



Fortunately for us, Drupal provides comprehensive tutorial for creating a custom module here:

http://drupal.org/developing/modules

Though it may seem to you that there is a lot to do here (which is true), it is always a good idea to walk through the tutorial so that you get a general idea of the process of creating your own module. If you are like me, and just want to hurry up and see a module in action, I suggest that you simply copy and paste the code to respective files and place them under the correct directory. I will explain this process more in detail below.

A simple Drupal module needs at least three files: .module, .info and .install files. The .module file, to put it in simple terms, defines the function of the module. It is also where the majority of the codes are located. The .info is a small file that contain metadata information about the modules and themes. Typically the contents of .info files look somewhat like this:

; $Id$
name = "Example module"
description = "Gives an example of a module."
core = 6.x

The above is an example taken from Drupal's tutorial. The name and description fields are required fields. The core field should indicate the version number of your Drupal installation. Drupal 6.x version is used for this example.

Last but not least, you must write your .install file. This file basically contains initial set up codes that are run once while installing the module. Typically (depending on the type of module), this file contains about a dozen lines of SQL query commands that creates the necessary tables in your database.

Overall, creating your custom Drupal module is not an easy task. I hope that the above information helps you to get a general idea. I will certainly post a more detail information once I make further progress with my project.

Tuesday, March 30, 2010

Managing Activities on Drupal

This is the second week of our current milestone and I am happy to say that we made a big progress forward. After working for a little while on this Drupal system with my team-mate, we realized that it was quite difficult to do a version control. One of the reason why this was so difficult is because we are working with two different operating systems. We faced numerous issues attempting to install the same system on my team-mate's Windows machine. When we finally got most of the functions to work, we have made many changes to the system that it made the version control process so much more difficult.

We then decided to host the system on a remote server. This way, both of us can make changes to the system simultaneously without having to worry about how to get the changes across to the other host. We will just have to make sure that we create back up copy periodically so that we could revert back to an older setting if need be.

After making the above changes, we decided to go ahead and work on the User/Admin activities. We began by searching for an appropriate Drupal module that are capable of this. We came across more than a couple of modules, such as Signup, webform, etc. The Signup module works closely with the existing module called Event, and it enables users to sign up for an event created by an administrator. This module seems to work perfectly well, however, we still need to figure out how to get this to work more closely to that of the mock up designs.

Another module we are experimenting with is called Webform. This module allows to create multiple field types. Using this module, we were able to create field types of an activity. The types that we made include start and end date, publish date, amount of kukui nuts earned, etc. We are still looking to find out a way to combined the above mentioned modules to create a system similar to that of the mockups.

Overall, it is a pleasant experience to be able to work on this system on a remote server. I feel that we are now much more efficient in our development. I hope keep up the work and finish the project by the end of the semester.

Tuesday, March 16, 2010

Preparing Drupal for Subversion

Have you ever wondered if you could put your web site/application running on a CMS up on a Subversion? That is what I have been working this week and I believe that I have come up with a solution.

The Drupal system, the Kukui cup app, that I have been working on now needs to be under a version control. One of the reason why I am doing this is because I am now working on the project as a group, rather than as an individual. Another reason is so that everybody else in the world can check this out if he/she desires.

My very first approach to version control my system was by putting it up on the subversion repository on my Google Project hosting website. This seemed to me, was the right way to do it at first. It turns out; however, that uploading all of Kukuicup system's content onto the repository requires a large amount of time. So much time that it seemed like my SVN client has stopped working all together. To my surprise, the size of the Kukuicup system happens to be around 21Mb, which I figure accounts for the painfully long upload time. I decided that this was not acceptable.

I realized after some thought that in fact we rarely make any changes to the web contents folder to begin with. The only time we make any changes is when we add new modules to the system or modify any of the CSS files. Therefore, I decided to simply compress the entire web contents folder and upload it onto the downloads section, which can be done with considerably less amount of time. The only remaining problem now is to figure out how to version control the database. I plan to achieve this by simply uploading the MySQL dump file to the repository. This would be useful since we will be making a lot of changes onto the database. The dump file is currently not uploaded to the repository for some security concerns, but I hope to have it up very soon. Following is an image of our Google Project hosting site.



















Following is the link to the project site if you would like to check it out:
http://code.google.com/p/kukuicup-drupal/