I seem to have a recurring problem with fully understanding how to build custom routers.

Who is the URL routing master? I've looked at Hannes' HP router which removes the id number from com_content article URLs and tried to tear it apart and study it, but I still seem to hit a wall when trying to build a router that does anything even slightly different.

I've done all the tutorials on docs.joomla.org and all that. I'm looking for someone who REALLY understands how to build custom URL routers and is will to help me wrap my head around them.

Any help is greatly appreciated.
-Jon

Tags: router, routing, url

Views: 314

Replies to This Discussion

This is something that I think everyone has a different approach to in my experience. We've also struggled with how to best implement the custom routers (the main problem being that the arrays do not have 'keys' but are simply an index).

With JForce we have decided to use loops to run through and check for the existence of various variables, personally I think that's a bit tedious and not the cleanest method though.

It really depends on the complexity of the component that you have written and what variables will be in your URL (and if they will always be present or if they could potentially not exist....if that makes sense).

Let me know if someone has a solution that works every time, would love to hear it!
The problem lies in the Joomla SEF architecture - probably for performance purposes url's are encoded / decoded on the fly and no database is used for maping. On encoding part this is easy - just drop keys and change values to whatever you would like them to be. But of course - no keys creates problems on decoding part, what you get is an indexed array of values. If parameter count doesn't change much and their structure is predictable this works ok, but with components with variable number of URL parameters this quickly becomes a nightmare.

Technically it's fairly easy, but it's logic can become quite complicated, especially on decode part. You need just 2 functions - one for encoding SEF url and the other to decode it back to real url:

In ComponentnameBuildRoute you do this for any parameter you wish to SEF:

if (isset($query['yourparameter'])) {
switch ($query['yourparameter']) {
case 1:
$segments[] = 'first_name';
break;
case 2:
$segments[] = 'second_name';
break;
case 3:
$segments[] = 'third_name';
break;
}
unset($query['yourparameter']);
}

And in ComponentnameParseRoute you just have to reverse what you did in BuildRoute - trick is that you have to do predict which segment is which parameter from the order of their appearance. If you would have just 1 parameter that would be no problem:

$vars = array();
switch ($segments[0]) {
case 'first_name':
$vars['yourparameter'] = 1;
break;
case 'second_name':
$vars['yourparameter'] = 2;
break;
case 'third_name':
$vars['yourparameter'] = 3;
break;
}
return $vars;


What I did in a more complex case with variable number of parameters is that I choose to SEF only a limited number (up to 5) of URL parameters that define wider areas like categories and subcategories or represent really important part (like hotel name) - and keep all others unSEFed. After that count people don't care/read them anyway. To satisfy Google use strings that actually mean something instead of using numeric values in key/ value pairs.

If you can afford it (if performance isn't your top priority) - I would say go for any of the real SEF components as Joomla built in SEF is faster but totally unflexible at the same time.
I also use an approach very similar to Klas's (so perhaps there is a 'generic' approach after all?) If the component is more complex, I first determine the viewname, and then I examine the various components of the query path (this is where I also try to find any matching Itemids from the menus if necessary). I then make sure that I know exactly in what order the segments array is built, but the view always comes first.
In the ComponentParseRoute I use a switch to determine how to build the SEF url. Like in Klas's example' it uses the view name as the condition, and then builds up the url for each case. I also use a count of the segments as a second condition to be met in some cases.
This only works if you know exactly how your urls are built up. Like Klas, I sometimes leave a few path elements out of the process, but usually no more than 1 or two (I don't see any shame in that :)
I would agree though, that writing a custom router can be a challenge. I have not used a third party solution though, I guess I shy away from that because I feel it takes away control.
Thanks for all the great replies.

Now time for me to get back to route writing.
URL routing with Joomla's framework is a very tricky job, that involves a lot of planning ahead with your component's development, compromises on flexibility and taming error sources that go with using URL routing. To round things up, there is very little documentation (at least I didn't find much) about the process.

On the up-side, it is very rewarding and the right approach to SEF (let alone the fact that all these SEO plugins out there are very thoughtful but will always be a p.i.t.a. for the end user, performance and ultimately for the developer).

The idea of the Joomla router.php files is simple in general:

One __parseRoute() function
One __BuildRoute() function

__parseRoute is used to translate the SEF URL to a key-value pair.

It receives "segments" as referenced parameter in form of an array with the numeric keys (which is the order of the segments in the URL), representing the pieces in the URL that Joomla does not handle. It should return an associative array with the keys representing the query parameter keys and the values representing the values of the query parameters (e.g. array('myparam'=>'myvalue')).

__buildRoute is doing the opposite. It is used to build the SEF URL that is used for any href dealing with your component. URLs in your component should use JRoute::_('nonsef string'); in order to get built.

It takes the query parameters as referenced associative array including those that Joomla handles (Joomla handles parameters like 'option', 'tmpl', 'Itemid' etc) and should return URL segments in form of an numeric array, where the keys represent the order in which the URL segments should appear in the URL and the values represent the text that should appear in the URL. Every item in the query array that was translated into a segment has to be unset (e.g. unset($query['myparam']), or it will be appended to the URL as normal query parameter. You can leave out some parameters if you decide not to SEFify it.

That's the whole thing. How you return your values for parsing and building is entirely up to you and you got the whole Joomla framework at your disposal (like JFactory, JRequest, JSite, but note that you have to take performance in consideration since there might be lots of links to parse for a page.

Also take into account, that URLs pointing to your component, do not necessarily have to be parsed when your component is loaded, so do not rely on any of your PHP classes already loaded.

A very useful method is to deal with performance issues for building routes is to have your non SEF parameter values use so called slugs (e.g. index.php?option=com_mycomponent&view=myview&content_id=2:myalias). Here, the alias (which you can use as segment) is already there, so you don't have to process the id and lookup the alias. In order not to break non-SEF configurations, you can use the recommended JRequest::getInt('[parameter]') method for integers, which returns your parameter value without the ':myalias' part as a nice by-product of proper input sanitation.

I hope I was able to help!

Kind regards,

Martin
This is the best documentation on Joomla SEF that I have come across. It's totally cleared up any confusions I had left. Thanks to you for posting this, and thanks to Jonathan for asking the question in the first place so that you could answer it.
Yes! Thank you everyone for your comments, especially Martin. Starting to make sense.

Babs said:
This is the best documentation on Joomla SEF that I have come across. It's totally cleared up any confusions I had left. Thanks to you for posting this, and thanks to Jonathan for asking the question in the first place so that you could answer it.

RSS

Badge

Loading…

© 2012   Created by Amy Stephen.

Badges  |  Report an Issue  |  Terms of Service