Creating a Site Module for Joomla 3.x – Part 5
The MVC Concept
Joomla components use the Model, View, Controller (MVC) pattern when they are written, and we will cover this in detail when we start writing components for Joomla. However, I just want to touch on the idea here just a little. When using a Model, View and Controller, your code is broken out into bits where each section of code is assigned a specific job to do. This makes maintaining the code easier because it is broken out in smaller chunks each having a specific purpose. So let me break down each function that the MVC pattern has.
First is the Controller. The controller should receive the users input, process it in some way and then act on it. Think of a remote for a DVD player. When you press the play button on the remote (controller), it sends the signals needed to the DVD player (the Model) to play the disk. The controller for a component in Joomla will examine the users input and then call methods in the model to get what it needs.
Next is the model. The Model’s job should be to retrieve data and return it. In our example above, when we press play on the DVD Remote (the controller), the controller tells the DVD player to get the video contents from the disk. The DVD player (the model) will access the disk and then start sending the data to your television, also known as the View. The model for a Joomla component will typically access the database and return the data to the controller.
Finally we have the view. The view’s job is to display the data that was returned from the controller. Continuing with our example from above, when the DVD player accesses the disk it will send the data that it retrieves to your television (the view). The television is only concerned about displaying the information to the end user. It does not care where the information came from or how it is retrieved. In a Joomla component the view is responsible for displaying the data that was returned from the model to the user.
Joomla modules on the other hand do not use Models, Views and Controllers in the classic sense, but the code can be broken down to resemble them and the end result is that the code is easier to debug and understand. We touched on this in part 3 of this tutorial series when we talked about the view or layout of the module. If you recall, we created the default view and called it statically from the modules PHP file. Later, when we start adding parameters to our module we will utilize other views for our module. So now that we understand what a view is for our module, what about the Controller and Model.
You can think of the modules PHP file as being the controller for the module. It is the file that Joomla calls when the module is loaded and this file will control getting the data it needs and passing that data to the view of the module. This leaves only to define a Model for the module.
If you examine the modules that are installed in Joomla you will discover that the PHP file for the module (the controller if you will) loads a helper class from another file. This helper class has the methods needed to get data from the database and returns it to the controller. This helper class can be thought of as a Model. It receives requests from the modules PHP file (the controller) and returns data based on that request back to the modules PHP file.
Some purist may say that I am being a little fast and loose with my definitions here, but the idea I am trying to pass along is that the MVC programming pattern does sort of fit into Joomla’s Module architecture and in the end will make coding and debugging our module easier. If for no other reason, it is broken into logical elements that make it easy to figure out where a problem is happening. If the data you are trying to display doesn’t look correct, you know that you should look in your view. If you are missing data, perhaps you should look in the helper class, etc.
Adding the Helper Class to our Module
To add the helper class to our module we need only to create a file to hold our helper class. If you look at the modules that are installed with Joomla you will see that this file is called helper.php and lives in that same directory as the modules PHP and XML file. Since standards matter for ease of portability and maintenance, we should not be any different. So in the root of your project directory create an empty helper.php file. Your project directory should look like the following with the addition of the helper file marked in red.
mod_random_quote/
mod_random_quote/helper.php
mod_random_quote/index.html
mod_random_quote/mod_random_quote.php
mod_random_quote/mod_random_quote.xml
mod_random_quote/language/
mod_random_quote/language/index.html
mod_random_quote/language/en-GB/
mod_random_quote/language/en-GB/index.html
mod_random_quote/language/en-GB/en-GB.mod_random_quote.ini
mod_random_quote/language/en-GB/en-GB.mod_random_quote.sys.ini
mod_random_quote/sql/
mod_random_quote/sql/index.html
mod_random_quote/sql/install.mysql.utf8.sql
mod_random_quote/sql/uninstall.mysql.utf8.sql
mod_random_quote/tmpl/
mod_random_quote/tmpl/default.php
mod_random_quote/tmpl/index.html
Now, open the helper.php file and add the following code:
<?php
/**
* Helper class for mod_random_quote module.
*/
abstract class ModRandomQuoteHelper {
public static function getRandomQuote() {
// database code goes here.
return "This is a returned quote.";
}
}
Now let’s discuss the code in this file briefly. We start with the <?php tag indicating this is a script and a comment that the contents of this file is the helper class for the mod_random_quote module. Next we define our helper class. The class name is composed of the module name in camel case with no underscores followed by the word Helper giving us the name of ModRandomQuoteHelper. Again, this is one of the conventions used in Joomla for naming classes. It is important to use this convention because there are parts of Joomla that create class names dynamically and this naming convention is used to derive the class name. Notice the class is created as an abstract class. This simply means that the class itself cannot be instantiated directly, and in our case we don’t need to. We only need a container to store our methods we want to use to access the data from the database. That brings us to the method declaration for getRandomQuote(). Notice it is public and static, meaning we can call this method without instantiating the class. We will flesh this file out more shortly, but for now notice that it simply returns a string that reads, “This is a returned quote.”. We will use this for testing before moving on to actually accessing the database to get a random quote.
In order to use our newly created class in our module, we will need to edit the modules PHP file to include it. Open mod_random_quote.php and make the additions marked in red.
<?php
defined('_JEXEC') or die;
// Include the mod_random_quote helper functions only once
require_once __DIR__ . '/helper.php';
$quote = ModRandomQuoteHelper::getRandomQuote();
require JModuleHelper::getLayoutPath('mod_random_quote', 'default');
The first line of code, require_once __DIR__ . '/helper.php';, will look in the current directory and load the helper class file. The require_once makes sure that we only import the code one time. Next we make a call to the method we created in the helper class to get the quote with the line of code that reads $quote = ModRandomQuoteHelper::getRandomQuote(); and assign it to the variable named $quote.
Now that we have the helper class written and the modules PHP file is calling the method we need to make a change to the template (or view) to make use of the data retrieved. Open the /tmpl/default.php file from your project directory and make the changes marked in red.
<?php
defined('_JEXEC') or die;
echo 'Random Quote Module';
echo '<br />';
echo $quote;
Here we have added a <br /> tag to add a line break and then echo our quote to the user.
With these changes in place we next need to update the manifest file so we can test. Open the mod_random_quote.xml file and add the line in red.
<?xml version="1.0" encoding="utf-8"?>
<extension type="module" version="3.5" client="site" method="upgrade">
<name>MOD_RANDOM_QUOTE</name>
<author>Joe Hildreth</author>
<creationDate>05 JUL 2016</creationDate>
<copyright>(c)2016 Joe Hildreth, All rights Reserved</copyright>
<license>GNU General Public License V2 or later</license>
<authorEmail>This email address is being protected from spambots. You need JavaScript enabled to view it.<;/authorEmail>
<authorUrl>http://www.myheap.com</authorUrl>
<version>1.0.0</version>
<description>MOD_RANDOM_QUOTE_DESCRIPTION</description>
<install>
<sql>
<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
</sql>
</install>
<uninstall>
<sql>
<file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
</sql>
</uninstall>
<files>
<folder>language</folder>
<folder>tmpl</folder>
<folder>sql</folder>
<filename>helper.php</filename>
<filename>index.html</filename>
<filename module="mod_random_quote">mod_random_quote.php</filename>
<filename>mod_random_quote.xml</filename>
</files>
</extension>
By now you have a grip on the manifest file and know that this line will include the file helper.php to be copied over when the module installs.
Testing the results
Zip up the module and install, publish it and give it a position and make it visible on all menus. The module should display like the image to the left. If all is well you should see the line, “This is a returned quote.”, indicating that our helper class was loaded and the method to return a quote was called and worked properly. If you had any issues, double check the content of your PHP and manifest files.
Getting a Quote from the Database
Now that we have the framework of our module in place by breaking out the functionality in different files, we can tackle getting one of our quotes from the database. Logically, getting information from the database is a job for the model, and in our module that means the helper class. Recall from above that we created a method in our class called getRandomQuote() whose job it will be to get a quote from the database.
Joomla has classes dedicated to working with the database and they are fairly simple to use. These classes are abstracted out and allow you to use the same code, regardless of the database server in which Joomla is running. These classes are JDatabaseDriver and JDatabaseQuery. The JDatabaseDriver class will return the connection to the database, creating one if it does not exist and is also responsible for returning the JDatabaseQuery object to make queries from the database. The JDatabaseDriver class object is available from JFactory. (For more information on JFactory see the Joomla execution cycle video or tutorial.) Let’s look at some code that will do this for us.
$db = JFactory::getDbo();
The above line of code will return the JDatabaseDriver object and store in in the variable $db. Pretty simple, don’t you think? Now that we have the database driver object, we can get a query object with the following code.
$query = $db->getQuery(true);
The above line of code will result in a new query object being returned and assigned to our variable called $query. Now, notice that we passed the value of true to the getQuery() method. This causes JDatabaseDriver to create a new empty query. If for some reason we needed to work with the last query made, we could pass false as a parameter to the method and JDatabaseDriver would return the last JDatabaseQuery object to us. For most practical purposes, we will always want a new empty query object and will pass true to this method. JDatabaseQuery object has lots of methods that help you create queries for accessing the database. These are probably best understood by example.
In our module, we want to get some random quote from the database. Well the first thing we need to figure out is how many quotes are there to work with. Fortunately, this is a simple query, all we have to do is select the count function on the table. The SQL code for this would look like this.
SELECT COUNT(*) FROM <tablename>;
Here <tablename> represents the table we want to do the count on. Creating the SQL with the JDatabaseQuery object is pretty simple and would use code like the following.
$query->select(“COUNT(*)”);
$query->from(“#__mod_random_quote”);
JDatabaseQuery allows us to build our queries in pieces and it takes the responsibility of assembling them together for us. The select() method aboves takes as a parameter the column names or SQL function (like count()) that we would use in a normal SQL SELECT statement. In this case we pass along the COUNT(*) function to it. Finally, the from() method takes as a parameter anything you would pass long in a regular SQL FROM statement. In this case, we are passing the database table of our module. Note that we have prefixed the table name with the #__ characters that Joomla will use to derive the database table prefix.
It should also be noted that these methods can be chained together. For example, the two lines of code above could be written as follows so feel free to pick your poison.
$query→select(“COUNT(*)”)->from(“#__mod_random_quote”);
With the JDatabaseQuery complete, we only need to pass this back to the JDatabaseDriver object like so.
$db->setQuery($query);
The setQuery() method will take the query that we created and store it in the database driver object. All that is left to do is have the driver execute and return the results to us.
There are a number of methods available to return the data from the database, and which one you use depends on the format of data you need returned back. Let me explain a little further. The methods available allow you to return a single result, a single row, multiple rows, a single column, data as an array, an associative array and as an object. The end result is that you have a lot of latitude with JDatabaseDriver. In our example we need only a single result, the number of rows in the table. We can do that with the following code.
$count = $db->loadResult();
The loadResult() method will return a single value from the database. In our case we executed the COUNT(*) function which returns the number of rows in the table which we expect only a single value. Once the value has been returned with loadResult() we assign it to the $count variable so that we can use it later.
To summarize, getting data from the database is pretty straight forward and for the most part we will always follow these same steps.
- Get the database driver from JFactory
- Get a Query object from the database driver
- Set up our query using the methods available from the JDatabaseQuery class
- Store the Query back into JDatabaseDriver
- Execute the query using the method that make sense for the data we expect to receive.
If you want to get a head start on using the database with Joomla, take the time to read the documentation which can be found at https://docs.joomla.org/Selecting_data_using_JDatabase
Now that we know how many rows are in the table, we can use this to select one randomly by using some php code like the following.
$recordNumber = rand(1, $count);
The above line of code will generate a random number between 1 and the number of rows we have in the table. In my database example from the last tutorial, this will be 50. Once we have this number then we can use it to select the specific record from the table. NOTE: The rand() function I am using above is a pseudo random number generator and does not generate cryptographically secure values, and should not be used for cryptographic purposes. Additionally, we assume that all the index, id values in the table are in sequential order with none missing. Since we ultimately have control over the data being stored in the database, we should experience no problems. But if, for example, we deleted a row from the table leaving that index empty, it is possible that the deleted index id would be randomized and then it not be in the database resulting in an error.
Now that we have the record number we want from the table, we can get a new Query object and create the query with the following code.
$query = $db->getQuery(true);
$query->select(“name, quote, source”);
$query->from(“#__mod_random_quote”);
$query->where(“id={$recordNumber}”);
The above code will generate the following SQL Query.
SELECT name, quote, source FROM #__mod_random_quote WHERE id=#
Keep in mind the following about the above query. Joomla will use your correct prefix for the table name above and the # I used after the id= is actually the random number we generated and assigned to $recordNumber.
With the Query out of the way, we expect only one row from the database to match our Query criteria, so we would want to use one of the methods from the JDatabaseDriver that returns a single row. We have a few to choose from. We can use loadRow(), loadAssoc() or loadObject(). Let me explain each briefly.
loadRow() will return one row from the database as an indexed array with the first column being at index zero. So a row would be accessed like the following:
$record[0]; //contains the name column value
$record[1]; // contains the quote column value
$record[2]; // contains the source column value
loadAssoc() is similar to loadRow() but it return the row as an associative array where each key is the column name. The row would be accessed like the following:
$record[‘name’]; //contains the name column value
$record[‘quote’]; // contains the quote column value
$record[‘source’]; // contains the source column value
Finally, loadObject() returns the row as a standard PHP object where each column will be accessed with the arrow operator. You can access the data like the following:
$record->name; //contains the name column value
$record->quote; //contains the quote column value
$record->source; //contains the source column value
Which method you choose really depend on how you plan to access the data in code. I will leave that as an exercise for you. Continuing with this example, I will use the loadObject() method. So to complete our code examples from above, we have the query finished and we need to submit the query to the JdatabaseDriver object and then execute the loadObject() method to retrieve the data. That can be accomplished with the following code.
$db->setQuery($query);
$record = $db->loadObject();
After executing the above code, the random quote will be loaded from the database and stored in the $record variable. Now let’s put it all together. Open the helper.php file and add the following lines marked in red.
<?php
/**
* Helper class for mod_random_quote module.
*/
abstract class ModRandomQuoteHelper {
public static function getRandomQuote() {
// database code goes here.
// Get the JDatabaseDriver object from JFactory
$db = JFactory::getDbo();
// Get the JDatabaseQuery object from the JDatabaseDriver object
$query = $db->getQuery(true);
// Build the query
$query->select("COUNT(*)");
$query->from("#__mod_random_quote");
// Save the query to the JDatabaseDriver object
$db->setQuery($query);
// Save the record count to a variable
$count = $db->loadResult();
// Randomize the record that we want
$recordNumber = rand(1, $count);
// Build the query for the record we want
$query = $db->getQuery(true);
$query->select("name, quote, source");
$query->from("#__mod_random_quote");
$query->where("id={$recordNumber}");
// Save the query to the JDatabaseDriver object
$db->setQuery($query);
// Load the row as a Standard PHP object from the database
$record = $db->loadObject();
// Return the row back to the caller
return $record;
}
}
Changing the view to show the quote
Up to this point we have made the connection to the database, grabbed our random quote and returned it to the caller. Remember we called our getRandomQuote() method from the modules PHP file and saved it to a variable named $quote. Then in the modules PHP file we call the template (or view) we wish to use. We need to update the view to use the $quote variable we returned from our helper. So open the /tmpl/default.php file and change it to the following.
<?php
defined('_JEXEC') or die;
echo "<p><b>{$quote->name}</b></p>";
echo "<p>"{$quote->quote}"</p>";
echo "<p><em>— {$quote->source}</em></p>";
Compared to the last version of this file we have removed the old echo statements and replaced it with three new ones. In the first line we display the authors name in bold. In the second line we display the quote wrapped in some quote marks and finally in the last line we display the source with a leading em-dash and a space. Save the file and let’s test out work.
Testing our work
We have not added any new files or folders since our last test so there is no need to make any changes to the module’s manifest file. All that we need to do is create a new archive and install it in the back end of Joomla. Remember to give it a module position, set it to published and set it to be visible on all menus in the event that you uninstalled it. If all went well your module should be displaying a quote like the image to the left. Click the home link a few times and you will see that the quote changes.
We have traveled a little way down the Joomla road in this series of tutorials, but we have much further to go and lots more exciting things to learn to write extensions for Joomla. In the next installment of writing a module for Joomla we will look at module parameters and how they are used. At this point though, we have a workable module, it works as designed and displays a random quote to the end user, but there are many things we can do to make it better and more robust. In the mean time do some reading on accessing the database with the link I gave you above. See you next time.
END OF TUTORIAL