2

Currently JRoute generates URLs for my component which look like this https://mysite.com/component/mycomponent/xxx, where I'm handling xxx in my component's router. Instead I'd like JRoute to generate a URL for the same location with https://mysite.com/myseflocation/xxx.

I've found four ways of achieving what I want, but I don't find any of them particularly satisfactory. All of my ideas require a menu item with alias myseflocation to which a view from my component is assigned. Its the creation and assignment of this menu item which is fundamentally where my problem lies.

My first idea was to include the Itemid=xx query string parameter in URLs passed into JRoute. The problem with this approach is that I'd be hard coding the menu Itemids all over the place which is a terrible idea as its tightly coupling the fixed code to the dynamic database.

The next idea I had, was to give my component a menuitem parameter, then the admin could create a menu item, assign one of the component's views to it, then assign that new menu item back to the component parameter. Whenever using JRoute, you could just get the menu item id from the component parameter.

The problem with this is that it requires the site admin to have knowledge of how my component works; they have to create a menu item and then assign that item back within the component. The problem with this is that if the menu item is ever removed, then the component parameter becomes broken unless the admin reassigns it.

The next two ideas are just really extensions on the last one, but requiring a little less intervention on behalf of the admin.

It may be possible to generate a hidden menu item on installation of the component, then use JFactory::getApplication()->getMenu() to fetch the menu's item id when needed, using the name of the menu. However, this would also suffer from the problem of an admin deleting the menu item and would also require quite a bit of additional code to save the menu item correctly and check for duplicates.

My final idea it to add code to my component router's build method, to get all menu items to which my component is assigned, like this:

$menu = JFactory::getApplication()->getMenu()
    ->getItems('component','com_sorn')

Then just get the first menu item from the resulting array and set it as the Itemid within the $query array.

The upside of this last method is that it can fall back to the /component/mycomponent/ path if no menu item is set. However, if the admin wanted two menu items to work with my component, only the first would generate correct URLs.

I guess the fundamental problem here is that I don't think Joomla allows components to claim first-level routes (first slug in URL), only menu items can do this. This means you're left with an item id you cannot know at component installation time and which could change in the future.

2
  • 3 comments. 1. Components are only called if the core router calls them, so no they cannot run without a menu item or the core component/x or nonsef option= methods. 2. A system plugin can intervene early in the life cycle and a set/override the component and or itemid and this allows for unorthodox routing options. 3. I don't understand what you are trying to achieve or why the menu itemid is relevant to the solution. Feb 16, 2020 at 1:41
  • @jamesgarrett I guess the root question is: In component code, how would you generate an SEF URL to another part of the component without hard coding the menu item id into the call to JRoute within the component code and tightly coupling code to database?
    – Dom
    Feb 16, 2020 at 13:52

2 Answers 2

1

(Not a proper answer, I'm afraid, just some thoughts – easier to write as an answer rather than lots of comments).

First I believe you're right about the need to have a menuitem which is associated with your component. Otherwise you're going to end up with the https://mysite.com/component/mycomponent/xxx format.

Secondly a good administrator will be concerned about the format of the URLs on the site, so I think it's good for the admin to know that your component output is associated with a specific menuitem (even if hidden). Also they may want to present that page slightly differently (eg different format or modules shown on that page), and any special webpage presentation aspects are defined via the menuitem. So it's good for the admin to be involved.

Having said that, I think that your idea of creating a hidden menu item in the installation is a good one, even if it means a bit more code. This will provide a good examplar for the admin. To help with handling duplicates you might find useful the AdminModel::generateTitle and AdminModel::generateNewTitle code, where Joomla itself has to deal with duplicates when it's auto-generating an alias.

Have you thought about a site which has multiple menus? Which one would you add the menuitem to? Maybe you have to generate one menuitem for each menu.

I'm not sure if your component supports multiple languages, but if it's a multilingual site then I reckon you'll need to add a menuitem to each of the menus for the different languages, and then when you include the language in the JRoute::_ call, Joomla should find your menuitem for the right language. (Remember, the admin may be presenting differently the different language versions of the website, eg using different templates, so you want different menuitems for your component for that case). And the admin might subsequently introduce a new content language with its own menu ...!

You mentioned about an admin wanting 2 menuitems to work with your component, and that may be true. So you'd need to work out how to decide which to use at any given time. For this you might find the menuitem Note field useful and match what's in it via some criterion with the data in your component.

1

From the answers comments and further scouring of the codebase, I think the answer is that, no, its not possible for a component to claim a route in Joomla without a menu item id associated with a view from that component.

The Joomla docs explicitly confirm this in this article, which says:

neither Joomla! nor any component router can create URLs with a different first [ segment of the path ]

Then this article goes on to add:

... the output of the component router is used after the first segment of a route, the first segment being the menu item's alias. This creates a difficult question: how is your router and/or other code to know which menu item to route through?

The solution described, which is used in the core, is to create a [componentname]HelperRoute class (the docs have an error , switching Helper and Route). The job of this class is, as the docs say is to:

find the most suitable menu item for a given piece of data to be displayed

There are examples of this in the core components helper route classes TagsHelperRoute and FinderHelperRoute, which both go looking for an appropriate menu item id and add it as a query string.

These helper methods are used when calling JRoute::_, like this:

JRoute::_(TagsHelperRoute::getTagRoute($item->id . ':' . $item->alias));

Overall, Joomla's routing system, with its menu item ids, in hindsight seems to be a bit of an architectural error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.