5 Case study 59
5.3 Drupal case study 64
5.3.1 Development environment 64
Drupal does not have an IDE specifically designed to develop new code for Drupal, therefore any IDE
capable of developing PHP code can be used. For the use cases in this research, the choice was made to
use Eclipse with the PHP development tools extension [56], since there was previous positive experience
with developing in Eclipse.
Extending Drupal is done by making extensions called modules. All that has to be done to make a new
Drupal module is to create a folder containing two files, a .info with information about the module, like
its name and description, and a .module file with the actual code. The folder containing the files must be
uploaded to the server in order to be used.
Figure 21: Drupal module file structure
The following setup was used to implement the use cases for Drupal: Pentium D 2x3Ghz, 2G Ram, Linux
Debian 2.6.32‐5‐amd64, Apache 2.2.16, PHP 5.3.3.7, MySQL 5.1.61, Drupal Commons 6.x‐2.4.
5.3.2
Usecases
This section implements the use cases described in section 5.2 implemented in Drupal. The work
required implementing these use cases, and the results of the implementation are given.
Use case 1: Create an extension
This use case gives some basic static information to the user. The goal of this use case is to determine
how to make a module and to discover any problems when developing new modules.
To show content at a page in Drupal using a module, a predefined function has to be implemented to
display this content. This function expects the developer to return an array containing the content to be
displayed by this module. The line “Hello world” is added to this array, and the array is returned. The
code from the file usecase1.module used to implement use case 1 is shown below. The $block array is
used to return the output of this module. The variable $op contains the operation, in this case there are
2 options: ‘list’ and any operation that is not ‘list’ . The code inside the if($op==”list”) is used by Drupal
to display the name of a module when displaying the list of available modules for a block. Inside the
$block[‘content’] is the actual content of the module.
After the module is uploaded to the server, it needs to be enabled at the module configuration page.
Finally, after the module is enabled, it needs to be placed in a block on the website. Each Drupal page is
divided into multiple blocks, for example header, sidebar and content. For each page, the content of a
block can be specified. A block can contain static information, but also modules. There are 2 ways to add
modules to the blocks. At the blocks page, /admin/build/block, modules can be added to blocks that
need to be displayed on every page, for example in the menu. Adding a module to a single page can be
done by creating a custom context for that page that contains the module, and use this context to add
the module to that page. Custom contexts can be used to trigger certain actions on certain conditions. In
this case an action is triggered to add the use case 1 module to the sidebar last block when the node
type is group. This adds the module to the group pages.
Figure 23: A Simple hello world use case in Drupal
Creating a new module in Drupal was straightforward with the available tutorials. The amount of code
required to only display one line is relatively high, 10 lines of code just to echo one line. Adding a
module to a single page using custom contexts was relatively complex.
function usecase1_block($op = 'list', $delta = 0, $edit = array()) { $block = array();
if ($op == "list") {
$block[0]["info"] = t('Use Case 1');
}else{
$block['subject'] = 'Use case 1'; $block['content'] = 'Hello world'; }
return $block;
}
Use case 2: Underlying platform functionality
The goal of this use case is determining how to use the functions of the underlying platform concerning
the currently logged in user. To achieve this goal, a module will be made which displays the username of
the currently logged in user. In this section, the steps required to achieve the goal are given.
A global variable containing information about the currently logged in user is available to the developer.
One piece of information is the username. The username is displayed in the same way as use case 1. The
following piece of code displays the username of the currently logged in user:
Implementing this use case was simple for Drupal, the username was available from the global object
$user. Drupal has a set of global variables and functions available, ranging from user information to
configuration variables, which makes accessing underlying platform functionality simple.
Use case 3: Access restriction
The goal of this use case is to restrict access to an extension to a certain role. To achieve this goal, only a
user with the role “usecase_viewer” is able to see the content of the module “usecase3”. Drupal offers
the possibility to create custom permissions, and an API function to check if a user has a role that
contains that permission. By calling this function with the required role as a parameter the platform
checks if the user has the required role, and if this is the case, access is granted. This allows access
restriction to the module. Once the custom permission is created at the administrator panel and the
check is added to the code, the next step that needs to be done is to create a role that contains that
permission, and assign this role to the user, which can be done from the configuration menu. In this case
the permission “view use case” was given, which grants permission to view the module. This permission
was given to the role “usecase_viewer”. Finally, the role “usecase_viewer” was given to the user.
Figure 25: Drupal roles
function usecase2_block($op = 'list', $delta = 0, $edit = array()) {
global $user;
$username = $user->name; $block = array(); if ($op == "list") {
$block[0]["info"] = t('Use Case 2');
}else{
$block['subject'] = 'Use Case 2'; $blockcontent = 'Hello '.$username;
$block['content'] = $blockcontent;
}
return $block;
}
It is not possible to give different permissions per instantiation of the module. It is however possible to
create a custom role for a user for a community, and assign permissions for a module to this role. This
way, since the role is only relevant for the instantiation of the module, permissions can be given to a
user per instantiation of the module, unless of course when there are multiple instances of a module
within community. So restricting access to a module is relatively easy, but limited.
Use case 4: Group data
The goal of this use case is to display the name of the community, the users and their roles for the
community the module is used in. After retrieving the group node id, which is a unique identifier for a
group, a query can be used to determine the group members. Displaying the group members and their
roles is done the same way as use case 1.
The code below shows a query to get the usernames from a certain group, and the code required to get
the current group id.
After the users from a group are known, the next step is to get the roles for the users for that group. For
each user this is done with a query:
Summary
Once the underlying functionality to retrieve the current group was known, implementing this use case
was straightforward.
Use case 5: External data consumption
The goal of this use case is to consume data from an external source using web services. To achieve this
goal, a SOAP client has to be implemented and integrated into a module. This SOAP client gets the local
time provided by a web service. The most straightforward to consume web services with Drupal is to use
the SOAP client from PHP [57]. This client takes the WSDL file from the web service, and creates a class
with the same functions as defined in this WSDL file.
$groupid =og_get_group_context()->nid;
$query = "SELECT users.name,users.uid FROM {users} users, {og_uid} og WHERE og.nid='%d' AND og.uid=users.uid";
$query_result = db_query($query,$groupid);
$zipcode = "10001";
$soapclient = @new SoapClient(
"http://www.ripedevelopment.com/webservices/LocalTime.asmx?wsdl=0" ,array("cache_wsdl"=>WSDL_CACHE_NONE));
$result = $soapclient->LocalTimeByZipCode( array("ZipCode"=>$zipcode)); $time = $result->LocalTimeByZipCodeResult;
Figure 28: Drupal use case 5 implementation
$query2 = "SELECT roles.name FROM {role} roles, {og_users_roles} our WHERE our.gid='%d' AND our.uid='%d' AND our.rid=roles.rid";
$query_result2 = db_query($query2,$groupid,$users->uid);
Figure 26: Drupal use case 4 implementation, getting group users
The syntax of the functions which should be called was not always clear due to bad documentation and
code complexity of the web service specification, so implementing this use case proved more
challenging than expected. After the correct syntax was determined, the information could be retrieved
from the SOAP call and this information was displayed the same way as use case 1. The code used to
acquire data from the web service called functions from the PHP API, not from the Drupal API.
Therefore, the difficulties that arose while implementing this use case do not give any indication about
the development in Drupal.
Use case 6: Automated tasks
The goal of this use case is to create an automated task that runs at a fixed time without user
interaction. This goal is achieved by creating CRON like functionality, in other words to assign some
scheduling functionality to call a predefined job at certain times. To create a CRON like function in
Drupal, the modulename_cron hook can be implemented. This function is called every time cron.php is
run. Running cron.php is up to the developer, by either using system crontabs, or by using a module that
calls cron.php on access.
The code shown below retrieves the local time from the web service from use case 4 and stores this
time in the database:
To our current knowledge, there is only 1 function which calls the hook_cron functions on all modules.
There is a function to check when the hook_cron was last called. It is up to the module developer to
determine if interval between the last function call and this function call was large enough and if any
action should be taken
Another thing to consider is the following: If – for some reason‐ a Cron job with a very short interval is
required, then cron.php must be called at a very short interval. The Cron functions of all the modules
will be called often; even when this might not be required since their interval is large, thereby creating
significant overhead.
Use case 7: Configuration page
The goal of this use case is to store settings for module. To achieve this goal, a configuration page where
these settings can be created and stored will be made. In Drupal, there are two places to place a
configuration page: As a subpage of the extension or at the configuration menu. The configuration menu
allows centralized access to all configuration pages, allowing easier management of the platform.
However, it does require that the user wanting to access to this administration page to have access to
the configuration menu. This configuration page should only be used to store settings relevant to every
instance of the module.
function usecase6_cron(){
$zipcode = variable_get("usecase5_greeting", "10001"); $soapclient = @new SoapClient(
"http://www.ripedevelopment.com/webservices/LocalTime.asmx?wsdl=0" ,array("cache_wsdl"=>WSDL_CACHE_NONE));
$result = $soapclient->LocalTimeByZipCode( array("ZipCode"=>$zipcode)); $time = $result->LocalTimeByZipCodeResult;
$query = "INSERT INTO {hoekie_usecase6}(time,adddate) VALUES('%d',NOW())"; db_query($query,$time);
}
To add a configuration page to the configuration menu in Drupal, the modulename_admin() hook has to
be implemented to create a configuration page. Also, the modulename_menu() hook has to be
implemented to create a menu item linking to the configuration page. This configuration page can be
used to set global settings for the module, not user/group specific settings. When storing configurations
per instance of the module/per group that uses the module, a subpage of the module should be
created. In this case, storing the information set in the configuration page is up to the developer.
The creation of this configuration page and creation of a link to this page is up to the developer. The
code below shows a simple form with 1 field where you can set a zip code:
Implementing a configuration page is easy in Drupal, there is functionality to retrieve and store the
information entered, as well as put restrictions on the values entered.
Summary
In this section, the results of the use case evaluation for Drupal were discussed. For each use case, the
implementation of that use case was given, along with some code examples. When the implementation
was not straightforward, or when limitations of the platform arose, these were also given in the report.
A summary of the results can be found in the evaluation per use case in section 5.5.2.
In the next section, the same use cases will be evaluated for Liferay.
5.4
Liferay
The previous section implemented the use cases created in section 5.2 using Drupal, and gave the
results. This section does the same for Liferay. First it discusses the development environment used to
implement the use cases for Liferay, followed by the results of the implementation of the use cases.
5.4.1
Developmentenvironment
Liferay Inc has created an IDE to develop new functionality for the Liferay portal, Liferay IDE. Liferay IDE
is an extension to the Eclipse IDE in the form of a set of Eclipse plug‐ins and offers functionality to create
Liferay extensions such as portlets and themes. For every use case in this chapter a new portlet will be
created, a more detailed description about creating portlets will be given later. Before a portlet can be
created, a project to contain the portlets must be created.
When creating a new Liferay project, several files will be generated. Among these files are several XML
files containing project settings and properties. Several folders are created where the files generated
function usecase7_admin() { $form = array(); $form['usecase7_greeting'] = array( '#type' => 'textfield', '#title' => t('Zipcode'), '#default_value' => variable_get('usecase7_zipcode','10001'), '#size' => 20, '#maxlength' => 20,
'#description' => t("The zipcode"), '#required' => TRUE,
);
return system_settings_form($form); }
when creating a new portlet will be placed. Finally, multiple libraries containing support functionality,
such as logging, axis and WSDL are included.
When creating a new portlet using the Liferay API, several things happen. Information about the portlet
is added to the projects settings XML files. A java class is created where the implementation of the
functionality of the portlet should be placed. The file view.jsp is created where the code to display the
content of a portlet should be placed.
Figure 31: File structure of a Liferay project with 1 portlet
The Liferay IDE has several ant scripts to deploy the created portlet on the server. Using these scripts
requires the server to be able to remotely deploy new portlets, or for the server to run locally.
To deploy the portlets containing the code for the use cases, the following server setup was used: AMD
Phenom 2x 3Ghz, 4GB Ram, Windows 7 64 bit, Tomcat 7.0.23, MySQL 5.5.22, Liferay Portal Community
Edition 6.1.0 CE
5.4.2
Usecases
This section implements the use cases described in section 5.2 in Liferay. It gives the work required
implementing these use cases, and the results of the implementation.
Use case 1: Create an extension
This use case gives some simple static information to the user. The goal of this use case is to determine
how to make a portlet and to discover any problems while developing a new portlet. To develop a
portlet, the steps from section 5.4.1 describing the creation of a new portlet must be followed. After the
portlet is created, the line “Hello World” to the can be added to the file that is displayed when calling
the portlet. The file that needs to be called on portal initialization can be changed at the portlets
configuration file, portlet.xml. By default when using the Liferay IDE to create portlets this file is view.jsp.
After adding the “Hello world” line the portlet is finished and can be deployed to the server. To show
this portlet to a user, a new page designated to contain the portlet should be created at the control
panel and the deployed portlet must be drag‐and‐dropped to this page.
Figure 32: A simple Liferay portlet
For this use case, the data to be shown was “Hello world” and to achieve this, the line “Hello world” was
added to the file view.jsp. Implementing this use case was straightforward.
Use case 2: Underlying platform functionality
The goal of this use case is figuring out how to use the functions of the underlying platform concerning
the currently logged in user. To achieve this goal, a portlet will be made which displays the username of
the currently logged in user. In this section, the steps required to achieve the goal are given.
To find the username of the currently logged in user, several steps are required. First, the id of the
currently logged in user must be retrieved. This user id can be retrieved from the renderRequest object,
which represents the request sent to the portlet to handle a render. This id can then be used to get a
User object from the Liferay class providing user information. This User object contains information
about the user, including its name. Displaying the name was done the same way as displaying hello
world from use case 1. The jsp code to be created by the developer to display the username of the
currently logged in user is shown below:
Implementing this use case proved more challenging than expected. Using the renderRequest to get the
user id was not straightforward, and this solution was only found after doing some research on the
Liferay forums. This is a typical issue when developing with Liferay and only using the API, for every class
the functions are given, but can be hard to find to correct class. The classes used concerning User and