7 minutes reading time (1495 words)

Extending Joomla!'s MVC Architecture

Ever feel like you're repeating the same tasks over and over while developing Joomla! extensions? It's a common feeling when developing for any framework but one thing that all frameworks have in common is that they make it incredibly easy to create blocks of reusable code.

If you're a Joomla! extension developer the best thing that you can possibly do at this moment is to stop thinking of Joomla! as a content management system. Right here, right now, drop every notion in your head that you're developing extensions for a CMS. Finished? Great.

When creating web applications within Joomla!, it's easy for us to think strictly in terms of content management and forget just how powerful the Joomla! framework is. Granted, that framework was developed specifically for creating a robust content management system. But you can leverage its power to create sophisticated programs that have nothing to do with content management and everything to do with web application development.

As an in-house developer; my bread-and-butter is creating extensions for my company's Joomla! powered suite of web sites. These custom extensions are full-blown web applications in their own right, powering some of the busiest and most process intensive areas of our site. All of this happens within the Joomla! framework.

Early on in my development, one thing I began to notice was that I was performing some of the same tasks over and over. Here's a list I jotted down, in no particular order:

  • Attaching Javascript and CSS files.
  • Creating forms.
  • Validating user input.
  • Accessing a web service.
  • Getting file paths.
  • Handling Ajax requests.

When developing applications there are a set of standard activities that tend to repeat themselves. For example, I frequently need to request data from web services that provide access to our data tracking system. It wasn't long before I started grasping for a way to abstract this tedious process into something that took only one function to perform.

So how do we go about ensuring that we aren't repeating ourselves?

First of all, let me dispel any notion of modifying the core Joomla! classes. It's tempting. Believe me, I know. But modifying the Joomla! core is something you should never do. It may seem like a quick fix but in one fell swoop you've broken any and all future upgrades to the system. Leave the core classes alone.

Preferably, you would create your own library in the libraries folder of the Joomla! install. For those of you developing standalone extensions for the general public, I realize this might not be an option. But keep reading. We will cover a solution for that issue after laying down some groundwork.

Model-View-Controller

Joomla! extensions revolve around the Model-View-Controller development paradigm, specifically, the JModel, JView, and JController classes. Just about everything that shows up on the screen is being handled in one way or another by these three core classes. Other classes play a part but these are the big three, the play-makers, the classes that make things happen. Unfortunately, they are also limited in use.

Don't get me wrong, these classes are very good at what they were designed to do. However, your needs are not the needs of the Joomla! development team. These classes were designed with the needs of the core extensions in mind and, let's face it, you aren't remaking the core extensions. You need something that isn't available. That's why you're developing extensions in the first place!

To demonstrate what I'm talking about let's do something common — attaching a Javascript file to the document header. It isn't difficult but it can quickly get repetitive. Here's how I would attach a Javascript file in the view class of my component.

php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view' );

class TestViewExample extends JView
{
public function display($tpl = null)
{
$document = JFactory::getDocument();
$document->addScript('/components/com_test/assets/javascript/popup_ads.js');

parent::display($tpl);
}
}

Retrieve the current document instance and use one of its methods to attach a Javascript file located in your component (this is personal preference — I prefer to keep scripts and stylesheets specific to extensions grouped together). However, what if we need ten Javascript files, plus a few CSS documents?

php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view' );

class TestViewExample extends JView
{
public function display($tpl = null)
{
$document = JFactory::getDocument();
$document->addScript( '/components/com_test/assets/javascript/popup_ads.js' );
$document->addScript( '/components/com_test/assets/javascript/grid.js' );
$document->addScript( '/components/com_test/assets/javascript/maphighlight.js' );
$document->addScript( '/components/com_test/assets/javascript/email.js' );
$document->addScript( '/components/com_test/assets/javascript/validate.js' );
$document->addScript( '/components/com_test/assets/javascript/tokenizer.js' );
$document->addScript( '/components/com_test/assets/javascript/tooltips.js' );
$document->addScript( '/components/com_test/assets/javascript/ajaxlib.js' );
$document->addScript( '/components/com_test/assets/javascript/header.js' );
$document->addStyleSheet( '/component/com_test/assets/css/main.css', 'text/css');
$document->addStyleSheet( '/component/com_test/assets/css/grid.css', 'text/css');
$document->addStyleSheet( '/component/com_test/assets/css/ui.css', 'text/css');
parent::display($tpl);
}
}

This is not an unforeseeable scenario. Highly interactive web pages (think full-blown Web 2.0) frequently have multiple Javascript/CSS files. It is, however, the same information with only a small difference repeated ten different times. Not only that, suppose that every extension you developed used the same basic structure of assets/javascript/file.js. Wouldn't it be great if you could simply type tokenizer.js and be done? You can!

Create a central location and start building

If you don't already have one, create a new directory in the /libraries folder of your Joomla! installation. This will operate as a central location for any custom classes that you create.

Note: This will make it easier to import your files when working. By using this structure you will be able to make use the jimport function for quickly including classes but you can also opt to use the more advanced JLoader class which will free you from having to keep your library in the Joomla! file tree.

My library will be called Custom, though you can certainly use any name that you wish. Inside of this new directory create a file called customview.php and place the following code inside of it.

php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view');

class CustomView extends JView
{
public $_assetpath; //path to the asset folder of the component
public $_document; //shortcut to the JDocument instance

public function __construct($config = array())
{
//Automatically include the JDocument instance
$this->_document = JFactory::getDocument();
//Save the path to our asset folder
$this->_assetroot = JURI::base(true).'/components/' . JRequest::getCmd('option') . '/assets/';
parent::__construct($config);
}

/**
* Attaches a Javascript file in the assets/javascript folder of the component
* @param $filename
*/
public function addScript($filename)
{
$this->_document->addScript($this->_assetroot . 'javascript/'.$filename);
}
}

What have we just done? We've created a class that inherits all of the powers of JView and added our own method, addScript, which will allow us to easily attach Javascript files stored in com_mycomponent/assets/javascript/. Since this is a generic class not tied to any specific component, the $_assetroot that we created and defined adapts to whatever component happens to inherit from this class. As long as that component follows the standard directory structure that you defined, the process of attaching files has just gotten a lot easier.

Notice that we have defined the magic method __construct(). If you take a look at the JView class, you'll notice that it defines __construct() and performs a lot of critical tasks necessary to the operation of the request that we just can't live without. You have a couple of options here — you could redefine all of these operations yourself, or could simply pass the responsibility over to JView, which is what we've done with the line of code, parent::__construct();. This allows us to perform our own work without having to repeat everything that JView already takes care of for us.

Note: This is an important concept to remember: when extending the core MVC classes you will almost always need to pass control back to the parent class. It is a good idea to study how JModel, JView and JController work before extending them.

Now that we have our own customized view class, how do we actually go about using it? If you don't already have one, put together a new component and create a view. Using the CustomView class, this is what our first example would look like.

php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'Custom.customview' );

class TestViewExample extends CustomView
{
public function display($tpl = null)
{
$this->addScript( 'popup_ads.js' );
parent::display($tpl);
}
}

Significantly less code, right? In fact, if you were to apply this to our ten file example from earlier, that process becomes a relatively simple loop (or write a method that takes an array of files).

I hope you're starting to see the potential here. Admittedly, this has been very simplistic example of the possibilities available to you, but as I pointed out earlier, your own needs will differ from everybody else's.

Once you get in the habit of abstracting repetitive tasks you'll find your development becoming much more streamlined and less of a typing chore. Think about exploring JController and JModel and try to think of ways you could save yourself time by extending those as well.

0
7 Simple Tips For Using Your Joomla! Site
 

Comments

Already Registered? Login Here
No comments made yet. Be the first to submit a comment

By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/