It's Friday - what a day to visit jfoobar!

 

JFishbone - A Joomla! application

What does it mean: A Joomla! application?

Well, Joomla! is a famous content management system but since its release 1.5 it is more than just a ready-to-use CMS application. Joomla! defines a framework for PHP developers who want to write their own application with the whole diversity of features like usage of templates, easy database access, administration interface, components and modules, and user and contact management right out of the box.

To show how this all works I coded a tiny application called Fishbone, which shows how to use the framework and how to structure such an application. All the example code here is drawn from Joomla!, mainly from the installation and the administration part of the CMS.

In our example we use a template to show a simple text output and provide different languages.

The structure of the application

The name of the application is fishbone, so our first task is to create a folder with this name. This defines the starting point of the application and contains the main file index.php which loads the libraries and executes the application object.

If you installed Joomla! on your local computer, you can call fishbone with http://localhost//fishbone.

Lets have a look at the index.php file:


/**
* Fishbone - a Joomla! Application
* created by Wolfgang Disch
*/
define( '_JEXEC', 1 );
define( 'JPATH_BASE', dirname( __FILE__ ) );
define( 'DS', DIRECTORY_SEPARATOR );

require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );

// create the mainframe object
$mainframe =& JFactory::getApplication('fishbone');

// initialise the application
$mainframe->initialise();

// render the application
$mainframe->render();

// return the response
echo   JResponse::toString();

From this file we can see the structure of a Joomla! application: The application folder contains a folder named includes, which contains the application specific files: defines.php, framework.php, application.php and others. The file defines.php specifies the globally used filepaths:


// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

//Joomla framework path definitions
$parts = explode( DS,   JPATH_BASE );
array_pop( $parts );

define( 'JPATH_ROOT', implode( DS, $parts ) );
define( 'JPATH_SITE', JPATH_ROOT );
define( 'JPATH_CONFIGURATION', JPATH_ROOT );
define( 'JPATH_ADMINISTRATOR', JPATH_ROOT.DS.'administrator' );
define( 'JPATH_XMLRPC', JPATH_ROOT.DS.'xmlrpc' );
define( 'JPATH_LIBRARIES', JPATH_ROOT.DS.'libraries' );
define( 'JPATH_PLUGINS', JPATH_ROOT.DS.'plugins' );
define( 'JPATH_INSTALLATION', JPATH_ROOT.DS.'installation' );
define( 'JPATH_THEMES', JPATH_BASE.DS.'templates' );
define( 'JPATH_CACHE', JPATH_ROOT.DS.'cache' );

// the new application
define( 'JPATH_FISHBONE', JPATH_ROOT.DS.'fishbone' );

In framework.php the files of the framework are loaded:


// no   direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

/*
 * Joomla! system checks
 */
error_reporting( E_ALL );
@set_magic_quotes_runtime( 0 );
@ini_set('zend.ze1_compatibility_mode',   '0');

/*
 * Joomla! system startup
 */
// System includes
require_once( JPATH_LIBRARIES.DS.'joomla'.DS.'import.php');

// Installation file includes
define( 'JPATH_INCLUDES', dirname(__FILE__) );

/*
 * Joomla! framework loading
 */
// Include object abstract class
require_once(JPATH_SITE.DS.'libraries'.DS.'joomla'.DS.'utilities'
                               .DS.'compat'.DS.'compat.php');

// Joomla!   library imports
jimport( 'joomla.database.table' );
jimport( 'joomla.user.user');
jimport( 'joomla.environment.uri' );
jimport( 'joomla.user.user');
jimport( 'joomla.html.parameter' );
jimport( 'joomla.utilities.utility' );
jimport( 'joomla.language.language');
jimport( 'joomla.utilities.string' );

Back in index.php we see how the application is created:


// create the mainframe object
$mainframe =& JFactory::getApplication('fishbone');

The factory class searches in /fishbone/includes directory where we have to provide a file named as application.php. This file contains the definition of the JFishbone object, which is a class derived from JApplication. Here is the constructor of the class:


// no direct access
defined( '_JEXEC' ) or die('Restricted access' );
/**
 * Joomla! Application class
 *
 * @final
 */

class JFishbone extends JApplication
{
  /**
   * Class constructor
   *
   * @access protected
   * @param array An optional associative array of 
   *    configuration settings
   * Recognized key values include 'clientId'
   * (this list is not meant to be comprehensive).
   */
   function __construct($config = array())
   {
     <strong>// OUR APPLICATION ID</strong>
     $config['clientId'] =   <strong>4;</strong>           
     parent::__construct($config);

     //Set the root in  the URI based on the application name
     JURI::root(null, str_replace('/'.$this->getName(), '',
                          JURI::base(true)));
   }

It defines a client ID for our application. But the creation of the new instance will fail! This is due to the fact, that deep in the parent object JApplication there is a call to a helper class


$info =& JApplicationHelper::getClientInfo($client, true);

The purpose of the call is to get information about registered applications. Unfortunately the mapping is done hardcoded in JApplicationHelper class in the Joomla! libraries. So we have to hack the core file /libraries/joomla/application/helper.php:


class   JApplicationHelper
{
  /**
   * Gets information on a specific client id.  
   *  This method will be   useful in
   * future versions when we start mapping applications in the database.
   * 
   * @access public
   * @param int   $id       A client identifier
   * @param Boolean $byName    If True, find the client by it's   name
   * @return mixed Object describing the client or false if not known
   * @since 1.5
   */
   function &getClientInfo($id = null, $byName = false)
   {
     static $clients;

     // Only create the   array if it does not exist
     if (!is_array($clients))
     {
        $obj = new stdClass();

        // Site   Client
       $obj->id  = 0;
       $obj->name = 'site';
       $obj->path = JPATH_SITE;
       $clients[0] =   clone($obj);
 
       // Administrator Client
       $obj->id  = 1;
       $obj->name = 'administrator';
       $obj->path = JPATH_ADMINISTRATOR;
       $clients[1] = clone($obj);

       // Installation Client
       $obj->id  = 2;
       $obj->name = 'installation';
       $obj->path = JPATH_INSTALLATION;
       $clients[2] =   clone($obj);
 
       // XMLRPC Client
       $obj->id  = 3;
       $obj->name = 'xmlrpc';
       $obj->path =   JPATH_XMLRPC;
       $clients[3] = clone($obj);

       // Fishbone Client                     /**/
       $obj->id  = 4;                      /**/
       $obj->name = 'fishbone';            /**/
       $obj->path = JPATH_FISHBONE;        /**/
       $clients[4] = clone($obj);             /**/
   }
   ...

We add the highlighted entries to register our application and so the creation of our application object will be successful !

The application chain

Now the application chain is executed: After creating the Object through the factory class JFactory, the methods initialise() and render() are executed. There might be additional methods for routing and dispatching, but we will keep it simple here.

The initialise method sets the language of the application:


 /**
 * Initialise the application.
 *
 * @access public
 */
 function   initialise( $options = array())
 {    
    // Give the user English
    if (!empty($options['language'])) {
      $options['language'] = 'en-GB';
    }

    // One last check to make sure we have something
    if ( !   JLanguage::exists($options['language']) ) {
      $options['language'] = 'en-GB';
    } 

    parent::initialise($options);
  }

In our example we can switch to German language if we call the method with a language parameter:



// initialise the application
$mainframe->initialise(array('language' => 'de-DE'));

Now comes the kernel of the application. The $mainframe->render method loads the template and renders it. The result is written to the body of the JResponse object. The name and path of the template is passed to the render method of the document, which is of type JDocumentHTML.



  $params = array(
   'template'  => 'default',
   'file'  => 'index.php',
   'directory' => JPATH_THEMES
  );

  $data = $document->render(false, $params);

  JResponse::setBody($data);

Rendering a template will substitute statements by the content of the named buffer component, which is set by a setBuffer method:



    $document->setBuffer( $contents, 'component');

Here we see the segmentation into template on one side and inner part on the other side which actually is a component. To keep the example simple we will set the contents directly from a dummy component, which we include into the render method.

Lets see how the render method looks like now:


 /**
  * Render the application
  *
  * @access public
  */
 function render()
 {
  $document =& JFactory::getDocument();
  $user  =& JFactory::getUser();
 
  $document->setTitle(JText::_('PAGE_TITLE'));

  // Define   component path
  define('JPATH_COMPONENT', JPATH_BASE.DS.'content');

  // Execute the component
  ob_start();
  require_once(JPATH_COMPONENT.DS.'hello.php');
  $contents = ob_get_contents();
  ob_end_clean();

  $params = array(
    'template'  => 'default',
    'file'  => 'index.php',
    'directory' => JPATH_THEMES
  );

  $document->setBuffer( $contents, 'component');  
  $data = $document->render(false, $params);

  JResponse::setBody($data);
 }

The component in hello.php is just a place holder to demonstrate how the application can make use of different components here to render in the template. Its content finally is assigned to $contents.

After rendering the contents of the page, the result is enclosed in the object JResponse. At the last line, JResponse is sent to the client.


     // return   the response
     echo JResponse::toString();

Now we are finished. The result looks very simple but you should remember what we achieved:

We developed an application with the full support of the Joomla! Framework libraries

  • We used JDocument, JDocumentHTML and their related methods to render documents.
  • We used a Template, which can be changed easily without modifying the code.
  • We already have a multi-language application, which we can extend to switch between these languages.
  • We introduced the component concept.

If you are interested you can download the contents of the fishbone folder as a archive file fishbone.zip here.

Here is a screenview of our application so far:

fishbone - a first view

This post is updated at - 2008-12-27 - with:

About the author Wolfgang Disch

Wolfgang is a seasoned IT professional working long years as head of software development and member of the executive team of a mobile phone distribution company. In these years he perceived the change from desktop software to web based applications. His vision is to support people with useful internet based services on mobile handsets which are easily available wherever they are.

More about Wolfgang Disch

Like it? Share it!

There are 3 comments posted.

# 1 - Posted by: Ercan Özkaya on 2008-12-20 22:37:17

It's really a nice post. I like using Joomla! as an application and it sure has lots of potential and not known so much.

One thing though, you don't need to hack core to include your application.

Note that if you don't pass any arguments to JApplicationHelper::getClientInfo it will return the client list by reference so that means we can add our class to the static variable that keeps app info.

Then it's a matter of adding a class to the array like this before calling JFactory::getApplication:

//Set the application information

jimport( 'joomla.application.helper' );

$info =& JApplicationHelper::getClientInfo();

$obj = new stdClass();

$obj->id = 4;

$obj->name = 'appname';

$obj->path = JPATH_APPPATH;

$info[4] = $obj;

unset($obj);

# 2 - Posted by: Wolfgang on 2008-12-21 16:52:08

Thank you, Ercan. You are right, no need to hack the core!

The best place seems to be in the JFishbone constructor right before calling the parent constructor.

Thank you for your assistance

# 3 - Posted by: Tom on 2008-12-22 10:51:40

Very good post to start using Joomla for application development and understanding the application chain.

Help for creating beautiful comments.

Enter Your Details:
Enter Your Comments:
I'm finished with the form Your form will be checked and you'll get a preview.
moovur promo

Blogging team

We have a team that works on the blogs presented on this site. Below you will find all present members who are actively working on blogs on this site.


Please contact us if you are interested in helping us out with the creation of the blogs.

Post translations

jfoobar has readers from all over the world and in many languages. If you create a translation of one of our posts and link to it than please let us know so we can add a link back to the translation at the original post.

JFoobar friends on Twitter

Follow JFoobar on twitter

Sponsored Links

Latest Comments

Aaron wrote:
2009-12-23 13:19:22 - Genius! Thanks, Wilco. I've been dying to take .
Posted in How to downlo .
Amy Stephen wrote:
2009-12-22 18:39:37 - Happy Birthday to one of Joomla!'s most noble - .
Posted in Mister Joomla .
Antonie de Wilde wrote:
2009-12-22 09:30:26 - Congrats Robin. Have a good day and watch out w .
Posted in Mister Joomla .
Robert wrote:
2009-12-22 08:51:02 - Happy Birthday Robin .
Posted in Mister Joomla .
Arno wrote:
2009-12-22 08:43:28 - Happy Birthday Robin, love your suit, you wife .
Posted in Mister Joomla .
Brian Teeman wrote:
2009-12-22 00:17:41 - Happy Birthday Robin, Welcome to the big four oh .
Posted in Mister Joomla .