Application control flow

This article provides a structured breakdown of the application control flow for the administrative interface provided by Joomla 3 to assist in tracing problems involving the Joomla 3 application framework and third party components, modules and plug-ins. It is a work in progress reverse engineered from the source code for Joomla 3.2 and, accordingly: (1) this article may not reflect the current or subsequent state of of the Joomla 3 code base; and (2) this article is liable to change at any time without necessarily being brought fully up to date according to the then current version of Joomla 3.

Modules and classes

JFactory - libraries/joomla/factory.php

JApplicationBase - libraries/joomla/application/base.php

JApplicationWeb - libraries/joomla/application/web.php

JApplicationCms - libraries/cms/application/cms.php

JApplicationAdministrator - libraries/cms/application/administrator.php

JAdministrationHelper - administrator/includes/helper.php

JUri - libraries/joomla/uri/uri.php

JSession - libraries/session/session.php

JSessionStorage - libraries/session/storage.php

JPluginHelper - libraries/cms/plugin/helper.php

Overview

PSUEDO CODE

  1. create JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase object using JFactory::getApplication();
    1. load JEventDispatcher object → JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase::$dispatcher;
    2. load JSession object using JApplicationAdministrator<JApplicationCms::loadSession($session) and JFactory::getSession() → JApplicationAdministrator<JApplicationCms<JApplicationWeb::$session;
    3. start the PHP session using JSession::initialise($input, $dispatcher), and JSession::start();
    4. load JRegistry object containing the Joomla 3 framework configuration → JApplicationAdministrator<JApplicationCms<JApplicationWeb::$config;
    5. trigger the 'onAfterSessionStart' event;
  2. call the JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase::execute() object;
    1. call JApplicationAdministrator::doExecute();
    2. call JApplicationAdministrator::initialiseApp($options [array()]);
    3. sub- call JApplicationAdministrator<JApplicationCms::initialiseApp($options [array()]);
    4. sub- set JApplicationAdministrator<JApplicationCms<JApplicationWeb::$config, calling JFactory::getConfig();
    5. import the system plugins using JPluginHelper::importPlugin('system');
    6. trigger the 'onAfterInitialise' event;
    7. call JApplicationAdministrator::route();
    8. import the system plugins using JPluginHelper::importPlugin('system');
    9. trigger the 'onAfterRoute' event;
    10. call JApplicationAdministrator::dispatch();
    11. import the system plugins using JPluginHelper::importPlugin('system');
    12. trigger the 'onAfterDispatch' event;
    13. call JApplicationAdministrator::render();
    14. sub- call JApplicationAdministrator<JApplicationCms::render();
    15. trigger the 'onBeforeRender' event;
    16. trigger the 'onAfterRender' event;
    17. trigger the 'onAfterCompress' event;
    18. trigger the 'onAfterRespond' event;

Detailed control flow

index.php → JFactory::getApplication('administrator') → JApplicationBase::JApplicationWeb::JApplicationCms::getInstance('administrator') →

Create the JApplicationAdministrator object

new JApplicationAdministrator : JApplicationCms : JApplicationWeb : JApplicationBase

Load the JEventDispatcher object

JApplicationAdministration[JApplicationBase]::loadDispatcher() { loads the event dispatcher }

Get the JSession object

JConfig::get('session') → ::getSession()

Load the application configuration

JApplicationAdministrator[JApplicationWeb]::fetchConfigurationData() { load JPATH_ROOT / configuration.php }

JLoader::register( 'JConfig', JPATH_ROOT / configuration.php );

new JConfig();

JApplicationAdministrator[JApplicationWeb]::$config { JRegistry } → JRegistry::loadArray | JRegistry::loadObject { enumerate array elements / object attributes and insert them into the JRegistry object }

JApplicationAdministrator[JApplicationWeb]::loadConfiguration();

JApplicationAdministrator[JApplicationCms::loadSession()

{

generate session name using JApplicationHelper::getHash($session_name ['administrator'])

calculate session lifetime (per configuration) * 60 or 900 seconds

JFactory::getSession($options) → JSession::initialise($input, $dispatcher) → JSession::start()

JEventDispatcher::trigger('onAfterSessionStart')

if session is new, or [expired?] JApplicationAdministrator[JApplicationCms]::checkSession() { initialise session object in the database using the session id }

}

Execute the application

JApplicationAdministrator[JApplicationCms]::execute()

JApplicationAdministrator::doExecute()

JApplicationAdministrator::initialiseApp($options [array('language' => JApplicationAdministrator::getUserState('application.lang')])

{

JFactory::getUser()

JApplicationAdministrator<JApplicationCms::initialiseApp($options)

{

JFactory::getConfig()

JFactory::getUser()

[ select default editor for the user ]

JPluginHelper::importPlugin($type ['system'], $plugin [null], $autocreate [true], $dispatcher [null])

{

JPluginHelper::load() { loads the array of plugins from #__extensions according the the relevant user's authority provided by the value of the column 'access'. }

for each identified plugin, JPluginHelper::getPlugin($type, $name), new Plg<$type><$name>($dispatcher, array('type' => $type, 'name' => $name))

}

}

JApplicationAdministrator::loadLanguage()

}

Route

JApplicationAdministrator::route();

JApplicationAdministrator::$uri → JUri::getInstance('SERVER') → JUri::construct($uri) → JUri::parse($uri) → JString::parse_url($uri) → parse_url($encoded_uri)

JUri::$scheme ('http' | 'https')

JUri::$user ('')

JUri::$pass ('')

JUri::$port ('')

JUri::$path ('')

JUri::$query ('') [after the question mark - ?]

JUri::$fragment ('') [after the hash mark - #]

JUri::$vars () [output of parse_str(JUri::$query) - in the form of an associative array]

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterRoute')

Dispatch

JApplicationAdministrator::dispatch();

JAdministrationHelper::findOption() → JApplicationAdministrator[JApplicationBase]::loadIdentity()

JFactory::getUser() → JFactory::getSession() → JFactory::createSession($options [array()]) → JFactory::getConfig() → JFactory::createConfig(JPATH_FLATFORM.'/config.php', 'PHP', '') → JRegistry::loadObject($config)

JSession::getInstance($handler ['database' from JConfig], $options [array( 'expire' => 15 * 60 seconds or 900 seconds )]) →

new JSession($handler, $options) → JSessionStorage::getInstance($store [$handler], $options)

JFilterInput::clean($store, 'word') [normalises the input]

[import storage/<$store ['database']>.php]

new JSessionStorageDatabase($options)

JSession::_setOptions($options) → session_id( { name, id, expire, security, force_ssl } ) →

JSession::_setCookieParams() → session_get_cookie_params() → session_set_cookie_params( { secure, domain, path, lifetime } )

 

→ JApplicationAdministrator[JApplicationBase]::getIdentity()

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterDispatch')

Render

JApplicationAdministrator::render();

JInput::getCmd('option', 'com_login') { get 'option', default to com_login }

Get the JInput object ($this->input), the component (JInput::getCmd('option', 'com_login')), (JInput::getCmd('tmpl', 'index'))

JApplicationCms::render();

JApplicationCms::triggerEvent('onBeforeRender');

JDocument::render($caching, $options);

JApplicationCms::triggerEvent('onAfterRender');

Compress

JApplicationAdministrator[JApplicationWeb]::compress();

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterCompress');

Respond

JApplicationAdministrator[JApplicationWeb]::respond();

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterRespond');