BzZzZ - ustvarjamo podobe logo
slovenščina
english
How to override Joomla 1.5. component router

Have you ever wondered how to change Joomla core component without hacking it?

While transferring an older site based on Joomla 1.0 to 1.5. I found out that com_contact router in 1.5. isn't working properly (at least in my opinion) as router is imposing category itemid on items even when direct menu links to those items exist. As parameters depend on itemid (it defines active menu and active menu parameters) it is impossible to change parameters of linked items when you are accessing them from a category list - they all will show whatever is set on the category. Fix itself is fairly easy, but as Joomla 1.5. is not actively maintained anymore (except security fixes) I couldn't push this fix trough Joomla trenches of mud to get it officially fixed. And even if this would not be the case - waiting 3 years before fix happens was not an option. What I could do is to change files directly and redo this for every security release that will come in the following years - or try to override this functions somehow.

Even before starting this quest it was clear it's not gonna be easy as 1.5. has hardcoded file inclusions all over the place and is missing checks to prevent double loading of the same class - something that was hugely improved in 1.7. (where you can override literally everything). In our case locations are hardcoded at least twice - JRouter has hardcoded an instance loading location and JRouterSite has a component routing function location. So 1.7. kind of trick with preloading a class before a framework loads it's own version didn't work and all I got was "Cannot redeclare a class.." error. Different kind of magic was needed.

Inspired by Joomfish database wizardry, here is the trick

Instantiate a JRouterSite object trough JRouter getInstance and replace it with your changed class object afterwards while leaving the rest of framework thinking it is still dealing with the original object.

Not so hard when you figure it out :)

Main part of the code is contained in system plugin that is fired onAferRoute as this is where initial routing object already exists and has important properties (sef on or not) already set. To avoid having to copy the whole JRouterSite class here is another trick - JRouterSite2 extends JRouterSite and so inherits all of its functions and properties and so it only needs to contain changed functions, not all of them.

In the code sample bellow I left out unimportant parts where function is just a copy/paste from Joomla. As you can see all we are doing is changing include location when component is com_contact and we are in the site context.

Probably not needed but still - you can use this to override any router. Just change the component name and ofc - change the included router :)

 

/** ensure this file is being included by a parent file */
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport('joomla.application.router');
require_once(JPATH_ROOT . DS .'includes' . DS . 'application.php');
require_once(JPATH_ROOT . DS .'includes' . DS . 'router.php');

class plgSystemComContactRouterOverride extends JPlugin {

public function __construct(&$subject, $config = array()) {
parent::__construct($subject, $config);
}

public function onAfterRoute() {

$app = JFactory::getApplication();
if ($app->isAdmin()) return;
$router = & JRouter::getInstance('site');
$options['mode'] = $router->_mode;
$router = new JRouterSite2($options);

// get the full request URI
$uri = clone(JURI::getInstance());
$result = $router->parse($uri);
JRequest::set($result, 'get', false );

}

}

class JRouterSite2 extends JRouterSite
{

function _parseSefRoute(&$uri)
{

....
// Use the component routing handler if it exists
$app = JFactory::getApplication();
if('com_contact' == $component && !$app->isAdmin() ) {
$path = dirname(__FILE__) . DS . 'comcontactrouteroverride' . DS . 'router.php';

} else {
$path = JPATH_SITE.DS.'components'.DS.$component.DS.'router.php';
}
...

}


function _buildSefRoute(&$uri)
{

...
// Use the component routing handler if it exists
$app = JFactory::getApplication();
if('com_contact' == $component && !$app->isAdmin() ) {
$path = dirname(__FILE__) . DS . 'comcontactrouteroverride' . DS . 'router.php';
} else {
$path = JPATH_SITE.DS.'components'.DS.$component.DS.'router.php';
}...
..

}
}

 

zip Installable plugin and com_contact router override

 

DISCLAIMER: No Ninjas were harmed while performing this magic

 
  • strateško usmerjeno
  • integrirano
  • s kreativnostjo pospešeno
  • učinkovito komuniciranje
© BzZzZ 2008
stik z nami    zaposlitev    kazalo strani