User

Over/Step by step to a Joomla Module - Data retrieval and styling

From Joomla! Documentation

< User:Over
module tutorial

This is a multiple article series on how to develop a module for Joomla! version Joomla 3.x. We go step by step from basic functionality to some more advanced. At the end of the tutorial we'll use your custom module to show you, how you can use the powerful output override ( = change ) methods provided by Joomla!. The only prerequisite for overrides is that the module or component comply to the Joomla! best practices. Navigate the articles in this series by using the navigation box to the right (the Articles in this series). Start with the first and follow them one by one. The next article builds on the knowledge and the files from the previous.

A Tip!

As the links on this page are references, you should open them in a new browser window/tab.

Should have's to complete this tutorial

You should have some knowledge in web technology but you don't have to be an expert at all. If you want to customise or even administrate a web site you will have to learn a little of everything e.g, Html coding, Css styling, Php programming, Sql database, using Javascript and about web servers. If you want to develop extensions for Joomla!, in small or large, you better start with a module before you try a larger project with a component. It is also a nice start to get knowledge on how to modify your sites template design. A Joomla! module is similar to a widget in other contexts. Even if plugins are the shortest extension type in sake of code, they require a little more advanced system knowledge to implement.


Introduction[edit]

In this step we will extend "Your module" to retrieve data from a database table in two ways, direct access to a table and using a components methods. You have to have installed the module you created in former parts of the tutorial, before you start to follow this part.

Data retrieval[edit]

As in the previous parts you copy a skeleton file to your module folder in your Joomla path of the server. This time you copy the helper.php file to the "root" of the module.

helper.php[edit]

 <?php
/**
 * package     Your module
 * copyright   Copyright (C) 2014 Joomla Doe
 * license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die( 'Restricted access' );

abstract class ModYourmoduleHelper
{
	/**
	 * Get data from table
	 * @return  array
	 */
	public static function getData($params)
	{
		//we will add some code here
	}
}

The top of the file looks like any other of our php files. Copy your own comment lines from one of the php files you have edited in the former parts of the tutorial. Then we have a class definition with a name following a convention you as well should follow. Mod + The module name + Helper. A comment block follows describing what the following function does. We will add our code within the function ( in developer language called method ). You have to read the coding standards or have a look in any Joomla! core php file to learn more about coding and commenting conventions.

We will use an article to have a litle more dynamic data example. If you didn't create an article earlier in this tutorial series do that now. Keep it short as it's only an example. In the Module Manager you open your module and under the option tab you choose your article example. You see the title but actually the article id number is stored as parameter value.

In the first example we'll get the article text by sending sql statements to the Joomla! database API.

helper.php - The sql commands[edit]

   	/**
	 * Get data from table
	 * @return  array
	 */
   	public static function getData($params)
	{
   		//get article id from module parameter
		$id  = $params->get('article_id', 0);
		if ( !$id )
		{
			return false;
		}
		//get the users authorisations
		$user       = JFactory::getUser();
		$groups     = implode(',', $user->getAuthorisedViewLevels());

		$db = JFactory::getDbo();
   		//get a db query object
		$query = $db->getQuery(true);
		//select article id, title and introtext
		$query->select(
			array(
				$db->quoteName('a.id'),
				$db->quoteName('a.title'),
				$db->quoteName('a.introtext'),
				)
		);
   		//from the article table
		$query->from($db->quoteName('#__content', 'a'));
		//id from parameter, we cast to integer
		$query->where($db->quoteName('id') . ' = '. (int) $id);
		// Only return if published
		$query->where($db->quoteName('a.state') . ' = 1 ');
		//and user is authorised to read
                $query->where($this->db->quoteName('a.access') . ' IN (' . $groups . ')');

		//uncomment this line to see the query string
		//echo $query;

		$db->setQuery($query);
		try
		{
	   		//get the article
			$result = $db->loadObject();
		}
   		//check error
		catch (RuntimeException $e)
		{
			//this is a module so we skip it if there are errors
			// in other cases we would show a message
			//$app = JFactory::getApplication();
			//$app->enqueueMessage($e->getMessage(), 'error');

			return false;
		}

		return $result;

	}

See the brief comments in the text about what we are doing here.

Important security issue: use $db->quote($field_value) to avoid so called "sql-injections" for none integer or float variables. Be very careful when you build sql queries.

db->quoteName('field_name') escapes the name database dependent. We can't describe more details to Joomla! sql queries within this tutorial. More in Accessing the database using JDatabase

As this is a module we don't show errormessages to the user. If there are errors the page will still be ok.

Copy the code to your helper.php replacing the method ( = function ) getData.


The helper file is loaded and run from mod_yourmodule.php. Open it and add the following between defined(... and require.

mod_yourmodule.php - Load helper class[edit]

    // Include the helper file that provide the data
   require __DIR__ . '/helper.php';

   //the class suffix from parameter
   $moduleclass_sfx = htmlspecialchars($params->get('moduleclass_sfx'));
 
  if ( !$article = ModYourmoduleHelper::getData($params))
   {
      //if error or article not found skip this module
      return false;
   }

   //uncomment this line to see the available fields
   //var_dump($article);

At the same time we get the class suffix from the parameter. Explained below. Now that you have the article data, we will change the output file to show it. Remember? /tmpl/default.php

default.php - Show article[edit]

defined('_JEXEC') or die('Restricted access');
?>
<div class="yourmodule<?php echo $moduleclass_sfx ?>">

   <h4><?php echo $article->title; ?></h4>

   <div><?php echo $article->introtext; ?></div>

</div>

After defined(... and the php closing tab we change the html. We use embedded php code to echo the title and the introtext. We add a module specific class $moduleclass sfx to the div tag. $moduleclass sfx is the class suffix the user can add in the Module Manager -> tab Advanced. This can be used for Css styling if multiple instances of the same module are enabled. e.g. you can test to reuse your module by choosing another article. We will style them in the next step.

Css styling[edit]

Best practice on a website is to try to keep all css styling in one file. As you don't know if the users template shows your module as designed, you have to include a css file. Not really for what we have above, but in a tutorial we do as if. You should use the parameters we created in a former part, to let the user of the module exclude your css. Described in the Overrides part of the tutorial.

We will not only prepare for loading css but also for images and javascript. Best practice is to store those files in subfolders of the Joomla media folder. Please don't ask why this folder was named media.

Create folder path/to/your/joomla/media/mod_yourmodule. In the folder where you unpacked the tutorial zip file you'll find a media folder. Open this and copy all three subfolders to the new folder in your web folder. It should result in something like this

...
/logs
/media
  ...
  /mod_yourmodule          *new directory*
    /css                   *new directory*
      yourmodule.css       *new file*
    /images                *new directory*
      doc.png              *new file*
      yourmodule-logo.png  *new file*
    /js                    *new directory*
      yourmodule.js        *new file*
      yourmodule_ajax.js   *new file*
  ...
/modules
...

Did you use your module name? You don´t have to, but it´s a good practice to use distinct names.

Add Css file[edit]

We include the module specific css file to the header of the html document.

default.php - Include Css file and image[edit]

defined('_JEXEC') or die('Restricted access');

JHtml::stylesheet('mod_yourmodule/yourmodule.css', false, true, false);
?>
<div class="yourmodule<?php echo $moduleclass_sfx ?>">

   <div class="row text-center">
      <?php echo JHtml::image('mod_yourmodule/yourmodule-logo.png', 'Yourmodule logo', '', true, false );?>
   </div>

   <h4><?php echo $article->title; ?></h4>

   <div><?php echo $article->introtext; ?></div>

</div>

With this code added yourmodule.css will be loaded from the path media/mod_yourmodule/css/ Be aware of the missing /css/ ! This is added by Joomla. The image will be loaded from the path media/mod_yourmodule/images/.

Let's test that the css is working by adding a few lines to the yourmodule.css file. Open it with the editor and add e.g. those lines that change text color. Do we have to mention the module name that was used as css class?

yourmodule.css[edit]

.yourmodule h4{
	color: #08c;
}
.yourmodule p {
	color: #005580;
}

On your frontend page the colors should have changed and an image added. Have a look! Be aware that your browser may have cached the css.

Update the xml and the zip file[edit]

Now we have to add the new files to the xml file and create an updated installation zip file.

Add the helper.php and the special media tag to the xml file.

mod_yourmodule.xml - Add helper.php[edit]

Add helper.php to the files tag.

	<files>
		<filename>helper.php</filename> 
		<filename>mod_yourmodule.xml</filename>
		<filename module="mod_yourmodule">mod_yourmodule.php</filename>
		<folder>tmpl</folder>
	</files>

mod_yourmodule.xml - Add media folder[edit]

Add the media tag between files and languages.

	</files>
	<media destination="mod_yourmodule" folder="media">
		<folder>css</folder>
		<folder>images</folder>
		<folder>js</folder>
	</media>
	<languages folder="langs">

Create the installation file[edit]

Now you copy all module files from the server to the path 'somewhere'/j_module_tutorial/new_module as in the 'Installation package' part of this tutorial. Create a new folder 'media' and copy the three folders from media/mod_yourmodule.

  .../new_module
      /langs
        en-GB.mod_yourmodule.ini
        en-GB.mod_yourmodule.sys.ini
        anyother-language.mod_yourmodule.in
        anyother-language.mod_yourmodule.sys.ini
      /language
        /en-GB
          en-GB.mod_yourmodule.sys.ini
        /anyother-language
          anyother-language.mod_yourmodule.sys.ini
      /media
        /css
          yourmodule.css
        /images
          doc.png
          yourmodule-logo.png
        /js
          yourmodule.js
      /tmpl
        default.php
      mod_yourmodule.php
      mod_yourmodule.xml

Create the compressed installation zip file as described in the 'Installation package' part of this tutorial.

That's it for this tutorial. Below we describe an alternative for data retrieval.

Use a component for data retrieval[edit]

Below is an alternative to using direct sql. You can use the methods provided by a component to retrieve the data. If you develop your own component, you can prepare methods for reuse, otherwise you can try to find a method in a components models to retrieve the data you want. Here we reuse the getItem method of the content component ( articles ). In this case you get all article data returned. If you use a lot of modules of this type on the same page, be a little aware of momory usage. If you want to test it, you only have to replace the getData method in helper.php.

To see the data available you can uncomment the var_dump line in mod_yourmodule.php.

helper.php Use of component[edit]

   	public static function getData($params)
	{
   		//get article id from module parameter
		$id  = $params->get('article_id', 0);
		if ( !$id )
		{
			return false;
		}

		$model = JModelLegacy::getInstance('Article', 'ContentModel', array('ignore_request' => true));

		$app = JFactory::getApplication('site');

		$model->setState('article.id', $id);
		$model->setState('list.offset', 0);

		// Load the parameters.
		$params = $app->getParams('com_content');
		$model->setState('params', $params);

		$user = JFactory::getUser();

		if ((!$user->authorise('core.edit.state', 'com_content')) && (!$user->authorise('core.edit', 'com_content')))
		{
			$model->setState('filter.published', 1);
			$model->setState('filter.archived', 2);
		}

		$model->setState('filter.language', JLanguageMultilang::isEnabled());
  		
 		return $model->getItem($id);;

Add javascript to the module[edit]

If you want to use javascript for yourmodule, here is an example. It loads the javascript file in the media/mod_yourmodule/js path and adds a script to the header of the html document.

Read more J3.x:Javascript Frameworks

default.php Javascript[edit]

   JHtml::_('bootstrap.framework');

   JHtml::script('mod_yourmodule/yourmodule.js', false, true, false, false, false);

   $document = JFactory::getDocument();
   $document->addScriptDeclaration('jQuery( document ).ready(function()
		{
			alert(\'I am an alert box!\');});'
		);

Add this code below the line that loads the css file if you want to test it.

  • We use jQuery so we have to load it before our own modules script. Here we load the Bootstrap framework that also includes jQuery. Use JHtml::_('jquery.framework') if you only need this.
  • We add our scriptfile "relative" to the media folder.
  • We add the script declaration directly to the document object. It gets added to the header in the html document.