Actions

J1.5

Difference between revisions of "Creating a simple module"

From Joomla! Documentation

m (Wilsonge moved page Creating a simple module to J1.5:Creating a simple module: Move to 1.5 namespace)
m (removing review)
Line 1: Line 1:
{{version/tutor|1.5}}{{review}}
+
{{version/tutor|1.5}}
 
== Basic Hello World Module ==
 
== Basic Hello World Module ==
  
Line 293: Line 293:
 
This is meant as an example and it can be extended in various ways.  
 
This is meant as an example and it can be extended in various ways.  
 
However - If you do that, you should also ask yourself if this is the right way to do things. Components do have real installers and this could be the best solution even though a module can be quicker to do.
 
However - If you do that, you should also ask yourself if this is the right way to do things. Components do have real installers and this could be the best solution even though a module can be quicker to do.
 
[[Category:Tutorials]]
 
[[Category:Module Development]]
 

Revision as of 15:58, 29 April 2013

Replacement filing cabinet.png
This Namespace has been archived - Please Do Not Edit or Create Pages in this namespace. Pages contain information for a Joomla! version which is no longer supported. It exists only as a historical reference, will not be improved and its content may be incomplete.

Basic Hello World Module

A Joomla! 1.5 Module is in its most basic form two files: an XML configuration file and a PHP controller file. The XML configuration file contains general information about the module (as will be displayed in the Module Manager in the Joomla! administration interface), as well as module parameters which may be supplied to fine tune the appearance / functionality of the module. The PHP file provides the controlling logic for the module. A very simple "Hello World" module might looking something like this.

/modules/mod_hello_world/mod_hello_world.xml:

!!! Note: it is very important, that XML file name matches module name. Otherwise, installer will install the module, but Joomla wouldn't show parameters and additional info stored in XML.

<?xml version="1.0" encoding="utf-8"?>
<install type="module" version="1.5.0">
    <!-- Name of the Module -->
        <name>Hello World - Hello</name> 
 
    <!-- Name of the Author -->
        <author>Ambitionality Software LLC</author> 
 
    <!-- Version Date of the Module -->
        <creationDate>2008-06-23</creationDate> 
 
    <!-- Copyright information -->
        <copyright>All rights reserved by Ambitionality Software LLC 2008.</copyright> 
 
    <!-- License Information -->
        <license>GPL 2.0</license> 
 
    <!-- Author's email address -->
        <authorEmail>info@ambitionality.com</authorEmail> 
 
    <!-- Author's website -->
        <authorUrl>www.ambitionality.com</authorUrl> 
 
    <!-- Module version number -->
        <version>1.0.0</version> 
 
    <!-- Description of what the module does -->
        <description>Provides a basic "Hello World" notice</description>
 
    <!-- Listing of all files that should be installed for the module to function -->
        <files>
        <!-- The "module" attribute signifies that this is the main controller file -->
                <filename module="mod_hello_world">mod_hello_world.php</filename>
                <filename>index.html</filename>
        </files>
 
    <!-- Optional parameters -->
        <params />
</install>

Basically, this XML file just lines out basic information about the module such as the owner, version, etc. for identification by the Joomla! installer and then provides optional parameters which may be set in the Module Manager and accessed from within the module's logic to fine tune its behavior. Additionally, this file tells the installer which files should be copied and installed. Notice that we DO NOT include a reference in the files section for the XML file.

/modules/mod_hello_world/mod_hello_world.php:

<?php
//don't allow other scripts to grab and execute our file
defined('_JEXEC') or die('Direct Access to this location is not allowed.');
?>
<p>
    Hello World
</p>
What happens when this module is loaded is that Joomla! includes (via the PHP include directive) the mod_hello_world.php file and stores the output into an output buffer which is then rendered onto the page output. This file would simply produce

Hello World

to the final page.

/modules/mod_hello_world/index.html:

<html><body bgcolor="#FFFFFF"></body></html>

This really just helps to ensure that a default page is displayed if direct access to the directory is attempted without listing all of the other files in the directory. It's not necessary, but is good practice.

To package this module for distribution and installation, simply zip the files together, e.g.,

% cd mod_hello_world
% zip mod_hello_world.zip mod_hello_world.php mod_hello_world.xml index.html

The resulting mod_hello_world.zip file may be uploaded and installed through the standard Joomla! 1.5 Extension Manager.

Real Joomla! 1.5 Style Module Implementation

Now that was easy...too easy. In fact, that was pretty much the simplest form of a module possible. In reality a module will probably be doing something much more substantial. Let's assume that our modules are going to be more complex - we need to take advantage of the MVC (Model View Controller) design pattern and consider using the following file layout for a "Hello World 2" module instead:

/modules/mod_hello_world2/index.html
/modules/mod_hello_world2/mod_hello_world2.php
/modules/mod_hello_world2/mod_hello_world2.xml
/modules/mod_hello_world2/helper.php
/modules/mod_hello_world2/en-GB.mod_hello_world2.ini
/modules/mod_hello_world2/tmpl/index.html
/modules/mod_hello_world2/tmpl/default.php

The differences to note here are that there are three additional files beyond what the "Hello World" module had, namely helper.php, tmpl/default.php, and the en-GB.mod_hello_world2.ini file. The purpose in adding the first two files is two-fold. Firstly, we separate the module's logic into the helper.php file to ensure that all of the thinking and data access is performed here and separate out the module's presentation / template into the tmpl/default.php file (the (X)HTML). I argue that this is just good programming - separating logic from presentation. There is a second advantage to this, however, which is that it will allow the HTML / presentation to be overridden easily by any Joomla! 1.5 template for optimal integration into any site. (Overriding module and component presentation in templates is beyond the scope of this article, however it should be addressed as it's really useful).

Let's take a look at what these files might look like and discuss what's going on.

/modules/mod_hello_world2/mod_hello_world2.php:

<?php
//no direct access
defined('_JEXEC') or die('Direct Access to this location is not allowed.');
 
// include the helper file
require_once(dirname(__FILE__).DS.'helper.php');
 
// get a parameter from the module's configuration
$userCount = $params->get('usercount');
 
// get the items to display from the helper
$items = ModHelloWorld2Helper::getItems($userCount);
 
// include the template for display
require(JModuleHelper::getLayoutPath('mod_hello_world2'));
?>

The important differences to note are that (1) we include a helper file which will be the work-horse of our logic and data access and (2) once we have our data, we just load a template which will use our data and render it as it sees fit.

/modules/mod_hello_world2/mod_hello_world2.xml

<?xml version="1.0" encoding="utf-8"?>
<install type="module" version="1.5.0">
    <!-- Name of the Module -->
        <name>Hello World 2 - Hello</name> 
 
    <!-- Name of the Author -->
        <author>Ambitionality Software LLC</author> 
 
    <!-- Version Date of the Module -->
        <creationDate>2008-06-23</creationDate> 
 
    <!-- Copyright information -->
        <copyright>All rights reserved by Ambitionality Software LLC 2008.</copyright> 
 
    <!-- License Information -->
        <license>GPL 2.0</license> 
 
    <!-- Author's email address -->
        <authorEmail>info@ambitionality.com</authorEmail> 
 
    <!-- Author's website -->
        <authorUrl>www.ambitionality.com</authorUrl> 
 
    <!-- Module version number -->
        <version>1.0.0</version> 
 
    <!-- Description of what the module does -->
        <description>Provides a random listing of registered users</description>
 
    <!-- Listing of all files that should be installed for the module to function -->
        <files>
        <!-- The "module" attribute signifies that this is the main controller file -->
                <filename module="mod_hello_world2">mod_hello_world2.php</filename>
                <filename>index.html</filename>
                <filename>helper.php</filename>
                <filename>tmpl/default.php</filename>
                <filename>tmpl/index.html</filename>
        </files>
 
    <languages>
        <!-- Any language files included with the module -->
        <language tag="en-GB">en-GB.mod_hello_world2.ini</language>
    </languages>
 
    <!-- Optional parameters -->
        <params>
        <!-- parameter to allow placement of a module class suffix for the module table / xhtml display -->
                <param name="moduleclass_sfx" type="text" default="" label="Module Class Suffix" description="PARAMMODULECLASSSUFFIX" />
 
        <!-- just gives us a little room between the previous parameter and the next -->
                <param name="@spacer" type="spacer" default="" label="" description="" />
 
        <!-- A parameter that allows an administrator to modify the number of users that this module will display -->
        <param name="usercount" type="text" default="5" label="LABEL USER COUNT" description="DESC USER COUNT" />
    </params>
</install>

The main differences to note here are that we have added a language file reference (we could have added more) and we added some parameters.

/modules/mod_hello_world2/helper.php:

<?php
defined('_JEXEC') or die('Direct Access to this location is not allowed.');
 
class ModHelloWorld2Helper
{
    /**
     * Returns a list of post items
    */
    public function getItems($userCount)
    {
        // get a reference to the database
        $db = &JFactory::getDBO();
 
        // get a list of $userCount randomly ordered users 
        $query = 'SELECT a.name FROM `#__users` AS a ORDER BY rand() LIMIT ' . $userCount  . '';
 
        $db->setQuery($query);
        $items = ($items = $db->loadObjectList())?$items:array();
 
        return $items;
    } //end getItems
 
} //end ModHelloWorld2Helper
?>

This helper class (note that it is named for the module name so that it doesn't collide with other class names) simply retrieves a list of all users in the database and randomly selects a subset of those based upon the number supplied as $userCount.

/modules/mod_hello_world2/tmpl/default.php:

<?php defined('_JEXEC') or die('Restricted access'); // no direct access ?>
<?php echo JText::_('RANDOM USERS'); ?>
<ul>
    <?php foreach ($items as $item) { ?>
    <li>
        <?php echo JText::sprintf('USER LABEL', $item->name); ?>
    </li>
    <?php } ?>
</ul>

Here we simply create an unordered HTML list and then iterate through the items returned by our helper (in mod_hello_world2.php), printing out a message with each user's name.

/modules/mod_hello_world2/en-GB.mod_hello_world2.ini:

LABEL USER COUNT=User Count
DESC USER COUNT=The number of users to display
RANDOM USERS=Random Users for Hello World2
USER LABEL=%s is a randomly selected user

Here we simply identify strings which appear in the module configuration file and the module template which appear in JText::_ or JText::sprintf statements. This allows someone to easily write a new language file without editing any of the HTML or code for the module.

Now all we have to do is zip up these files, as in:

% pwd
/somesite/modules/mod_hello_world2
% zip -r ../mod_hello_world2.zip *
% ls ..
mod_hello_world2.zip

The resulting mod_hello_world2.zip file is ready for installation and distribution. When the ZIP file is installed, the en-GB.mod_hello_world2.ini file is copied to /language/en-GB/en-GB.mod_hello_world2.ini and is loaded each time the module is loaded. All of the other files are copied to the /modules/mod_hello_world2 subfolder of the Joomla! installation.

Joomla! 1.5 Database installation usage

Modules should in general not interact with the database except for normal operations (SELECT, UPDATE, INSERT, DELETE). But in some cases it might be needed to ALTER or even CREATE tables, even though it is not recommended. There is no common practice to this, but here is one way of doing just that:

Add a module parameter that to the manifest:

        <params group="advanced">
                <param name="is_installed" type="radio" default="0" label="Is module installed?" description="Only use this if you know the consequences! Click No to recreate database">
                        <option value="0">No</option>
                        <option value="1">Yes</option>
                </param>
        </params>


Then you can use the parameter to switch the state. Since the module parameters is already loaded from the database at this point, any overhead should not be noticable this way.

// put this in the module function. 
function myModuleReInstall() {
        if (!$params->get('is_installed')) {
                $database =& JFactory::getDBO();
                $query = "CREATE TABLE IF NOT EXISTS `example` ( `id` INT, `data` VARCHAR(100) );";
 
                $database->setQuery($query);
                $result = $database->query();
 
                $params->set('is_installed', 1);
        }
}

This is meant as an example and it can be extended in various ways. However - If you do that, you should also ask yourself if this is the right way to do things. Components do have real installers and this could be the best solution even though a module can be quicker to do.