J2.5

Creating a System Plugin to augment JRouter

From Joomla! Documentation

The "J2.5" namespace is a namespace scheduled to be archived. This page contains information for a Joomla! version which is no longer supported. It exists only as a historical reference, it will not be improved and its content may be incomplete and/or contain broken links.

JRouter Modifications[edit]

The Joomla! Router can be modified with additional rules by using the attatchBuildRules and attatchParseRules methods. Ideally, this can be done from a system plugin so these rules will apply globally.

Here are 2 examples of modifying JRouter using rules and a System Plugin. One will augment the results returned by JRouter while the other will completely replace the results returned by JRouter

Augmentation[edit]

JRouter returns an array of variables which are then used through the API by JInput to override the actual _GET/_POST/_REQUEST variables. If you merely want to augment the variables being returned, then this is straightforward.

Joomla 2.5

class plgSystemMyRouterAugmentor extends JPlugin
{
	/**
	 * @return  void
	 */
	public function onAfterInitialise()
	{
		$app = JFactory::getApplication();

		// Get the router
		$router = $app->getRouter();

		// Add my own rule:

		// Create a callback array to call the augmentRoute method of this object
		$augmentRouteCallback = array($this, 'augmentRoute');

		// Attach the callback to the router
		$router->attachBuildRule($augmentRouteCallback);
	}

	/**
	 * @param   JRouterSite  $router  The Joomla site Router
	 * @param   JURI         $uri     The URI to parse
	 *
	 * @return  array  The array of processed URI variables
	 */
	public function augmentRoute($router, $uri)
	{
		$vars = array();

		// Do something to the vars
		$vars['augment'] = 'succeeded';

		/**
		 * In this case, now to any Joomla! component/module it will look like
		 * ?augment=succeeded was in the url
		 */
		return $vars;
	}
}

Replacement[edit]

JRouter returns an array of variables which are then used through the API by JInput to override the actual _GET/_POST/_REQUEST variables. If you want to completely replace these variables, this takes a bit more work. In this case you may need to call the parse method in a sandbox to find out what would have been the results. You can then add/delete/modify those results. Finally, before returning those results to JRouter for the site itself, you need to flag JRouter so it doesn't continue to process the results.

Joomla 2.5

define('ROUTER_MODE_SKIP_SEF', 2);
define('ROUTER_MODE_SKIP_RAW', -1);

class plgSystemMyRouterReplacor extends JPlugin
{
	/**
	 * @return  void
	 */
	public function onAfterInitialise()
	{
		$app = JFactory::getApplication();

		// Get the router
		$router = $app->getRouter();

		// Create a callback array to call the replaceRoute method of this object
		$replaceRouteCallback = array($this, 'replaceRoute');

		// Attach the callback to the router
		$router->attachBuildRule($replaceRouteCallback);
	}

	/**
	 * @param   JRouterSite  &$router  The Joomla Site Router
	 * @param   JURI         &$uri     The URI to parse
	 *
	 * @return  array  The array of processed URI variables
	 */
	public function replaceRoute($router, $uri)
	{
		$app = JFactory::getApplication('site');
		$vars = array();

		// Get the true router
		$siteRouter = $app->getRouter();

		/**
		 * to avoid a recursion trap, we need to make sure that only
		 * the site router can call us!  We could have removed our own
		 * rule the myRouter...but that would only work
		 * inside our own method!  If someone else is also
		 * doing the same thing, we would have an ugly little
		 * recursion where they call parse which calls us
		 * and then we clone router and call parse which calls them
		 * back, and forth and back and forth
		 * friends don't let friends use recursion!
		 */

		if (spl_object_hash($router) != spl_object_hash($siteRouter))
		{
			// Recursion detected -> abort!
			return $vars;
		}

		/**
		 * we still want to clone the router passed to us, not the true router
		 * since the rules might be different
		 */

		$myRouter = clone $router;

		// Now use the power of Joomla! to parse this uri!
		$vars = $myRouter->parse($uri);

		// What is the menu id?  What is the airspeed velocity of an unladen swallow?
		$menuId = isset($vars['itemId']) ? $vars['itemId'] : 0;

		// Please be smarter than this.  Load the menu and check the config.  Do something
		if ($menuId == 67)
		{
			// Change the option to be a different component.
			$vars['option'] == 'com_my_custom_component';
		}

		/**
		 * $vars has both the merged values of what would have been calculated and our changes
		 * So force the siteRouter to skip more processing - no reason to process it twice!
		 * $router->setMode(JROUTER_MODE_RAW);
		 * if the router mode is RAW - integer 0, then _parseRawRoute will be called by JRouter
		 * $router->setMode(JROUTER_MODE_SEF);
		 * if the router mode is SEF - integer 1, then _parseSEFRoute will be called by JRouter
		 * if we set it to something which is NOT SEF or RAW, nothing is done to it
		 * false or null would be a logical choice,
		 * but since the comparison is == not === false, null and 0/RAW are the same
		 * therefore we defined our own constants.
		 * SEF/RAW is a binary condition of either a positive integer or not a positive integer[0]
		 * so we extend that so SKIP_SEF becomes 2 so the if clause will fail, but anything else
		 * counting on checking for if mode > 0 will work
		 * and SKIP_RAW is -1, so anything counting on checking mode <=0 will work
		 * if it is not 0 or 1, then we don't change it because something else
		 * already triggered the skip.
		 */

		$mode = $router->getMode();

		if ($mode == JROUTER_MODE_RAW)
		{
			$router->setMode(ROUTER_MODE_SKIP_RAW);
		}

		if ($mode == JROUTER_MODE_SEF)
		{
			$router->setMode(ROUTER_MODE_SKIP_SEF);
		}

		// Return our custom variables
		return $vars;
	}
}