? ? ? Failure

User tests: Successful: Unsuccessful:

avatar izharaazmi
izharaazmi
27 Jun 2017

Redo of #11060

Most of the work was originally done by @andrepereiradasilva. This is a redo of his work and more additions from me.

Summary of Changes

This PR is for allowing JRoute to generate URL's from admin to site and vice-versa.

This is a current problem especially if you are trying to make links from the backend to the frontend.

So, with this PR, there is no need anymore to make special code just to get the frontend link from the backend. With this PR we just need to use JRoute, like all other links. The same will work to links from frontend to backend. After this PR, no need to hardcode frontend to admin links.

We will be able to use following syntax:

// Build a frontend URL irrespective of in which context (site/admin) the code is running
JRoute::link('site', $url, $xthml = true, $ssl = null);

// Build a backend URL irrespective of in which context (site/admin) the code is running
JRoute::link('administrator', $url, $xthml = true, $ssl = null);

This should not affect the existing JRoute::_() method.

Testing Instructions

  • Test various URLs for different extensions (articles, menu items, etc).
  • You should try with the several combinations of site settings like:
    • SEF/non-SEF
    • With or without URL rewriting
    • With or without multi-language (i.e. with or without language filter plugin enabled).

Test 1: Links from admin to site

  • Use latest staging with sample data from at least two languages (en-GB, fr-FR)
  • Add to isis template index.php file...
$app = JFactory::getApplication();
$app->enqueueMessage('1. Admin to Admin: ' . JRoute::_('index.php'));
$app->enqueueMessage('2. Admin to Admin: ' . JRoute::_('index.php?option=com_content'));
$app->enqueueMessage('3. Admin to Site: ' . JRoute::link('site', 'index.php?option=com_content'));
$app->enqueueMessage('4. Admin to Site (MutilLanguage 1): ' . JRoute::link('site', 'index.php?option=com_content&lang=fr'));
$app->enqueueMessage('5. Admin to Site (MutilLanguage 2): ' . JRoute::link('site', 'index.php?option=com_users&lang=en'));
  • Open any admin page. Check the URL in resulting message are correct.

Test 2: Links from site to admin

  • Add to protostar template index.php file...
$app = JFactory::getApplication();
$app->enqueueMessage('1. Site to Site: ' . JRoute::_('index.php'));
$app->enqueueMessage('2. Site to Site: ' . JRoute::_('index.php?option=com_content'));
$app->enqueueMessage('3. Site to Admin: ' . JRoute::link('administrator', 'index.php?option=com_content'));
  • Open any frontend page. Check the URL in resulting message are correct.

Test 3: Code Review

Do a code review.

Test 4: Current URLs

Check if current URL generated by JRouter are exactly the same, i.e. no change in current URL.
Probably the best is to leave the patch applied for some time, while you do other things and check there are no problems with the current URLs.


Thanks to @mbabker, @ggppdk and @infograf768 for helping out with this one.

Maintainers, to make sure that are no unintended consequences it would be good if this can be also reviewed from someone that understand the Router better than I do.

2ad9ffd 9 Jul 2016 avatar andrepereiradasilva cs
0f1d95b 9 Jul 2016 avatar andrepereiradasilva cs 2
avatar izharaazmi izharaazmi - open - 27 Jun 2017
avatar izharaazmi izharaazmi - change - 27 Jun 2017
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 27 Jun 2017
Category Libraries Front End Plugins
avatar izharaazmi izharaazmi - change - 27 Jun 2017
Labels Added: ?
avatar izharaazmi
izharaazmi - comment - 27 Jun 2017

@mbabker Please review the changes now. I have kept the magic method and it does not ignore any errors. If you suggest I can also remove that altogether.

avatar izharaazmi izharaazmi - change - 27 Jun 2017
The description was changed
avatar izharaazmi izharaazmi - edited - 27 Jun 2017
avatar mbabker
mbabker - comment - 2 Jul 2017

I started digging into the test problems. We're in dependency hell.

Problem 1 - TestMockApplicationCms::getMethods() needs to include the getName method
Problem 2 - For JPaginationTest, need to add this line to configure the application mock in the setUp method (note that there will be some places that need to change the mock return to administrator in that test class)

$app->expects($this->any())->method('getName')->willReturn('site');

Problem 3 - JApplicationCms::getRouter() is static, it cannot be mocked, so we have to work with a real router (or use Reflection and push a mock into the JRoute::$_router property)
Problem 4 - JRouter::getInstance() does not support constructor injection of the application and menu objects for the JRouterSite subclass, so there is no way to inject stuff, meaning that code is falling onto the defaults
Problem 5 - The JRouterSite constructor calls JApplicationCms::getInstance('site'), this tries to create a JApplicationSite object with default behaviors since there isn't a mock application set up in JApplicationCms::$instances, and this ultimately leads up to a session start failure
Problem 6 - I got too deep into this and said "no more" πŸ˜†

avatar wilsonge
wilsonge - comment - 2 Jul 2017

So if you change https://github.com/izharaazmi/joomla-cms/blob/c7dd17d70bebe41230c28140612eccce5d727506/libraries/joomla/application/route.php#L87 to be if (!isset(self::$_router[$client])) (i.e. allow $client to be null), then unit tests pass and effectively replicate the current behaviour (admittedly the incorrect behaviour).

avatar mbabker
mbabker - comment - 2 Jul 2017

Well, good thing JRouter isn't abstract then.

avatar laoneo
laoneo - comment - 3 Jul 2017

If we are going the way in the pr #16940 that we try to move away from the static JRoute class and make the function as part of the router class itself, then we can solve this issue here as well. The SiteRouter and AdministratorRouter would then both have a route function which creates a link then accordingly to Site or Administrator.

avatar laoneo
laoneo - comment - 3 Jul 2017

It would then end up in a way that you can do Joomla\CMS\Router::getInstance('site')->route() or when you want the admin url Joomla\CMS\Router::getInstance('administrator')->route(). Or if you want to go trough the app then something like CMSApplication::getInstance('site')->getRouter()->route() will also work.
In J4 it lets you then even inject the proper router and you can do the route (or if you want to name it link) function.

avatar izharaazmi
izharaazmi - comment - 3 Jul 2017

We need to make sure that Joomla\CMS\Router::getInstance('administrator')->route() approach doesn't interfere with the session start thing too.

I think JRoute methods can be a proxy to this method too. We can keep it or drop it in 4.0

I have a grey recall about something like we are trying to drop the getInstance()methods. Isn't that true?

avatar laoneo
laoneo - comment - 3 Jul 2017

approach doesn't interfere with the session start thing too

Good question, but I don't think there is an issue as all what the _ function does is to add some stuff around the router->build function.

Yes the getInstance will become deprecated, but there will be then other ways to get a router. So the important part is that the function should not be static and be on the router itself.

avatar izharaazmi
izharaazmi - comment - 3 Jul 2017

The JRoute::link is currently failing when trying to implement router instantiation for the other client application already. Thats why I am concerned for the same thing in the proposed route method.

avatar laoneo
laoneo - comment - 3 Jul 2017

Don't get you. Can you elaborate it more please?

avatar izharaazmi
izharaazmi - comment - 3 Jul 2017

Please read comment above by @mbabker. If that doesn't help too, sure I
would try to elaborate myself.

avatar mbabker
mbabker - comment - 3 Jul 2017

In the test suite we basically need to use Reflection and drop a mock router into JRoute when testing, or use Reflection and drop mock application classes into JApplicationCms. Since JApplicationCms::getRouter() is static, it can't be mocked, and that's really where trying to fix the test issues in this PR starts falling apart.

avatar laoneo
laoneo - comment - 3 Jul 2017

If we move the function to the router then we have the application injected. Would that help?

avatar mbabker
mbabker - comment - 3 Jul 2017

No. The base router class and the admin router class don't need the application object, so those are fine generally. JRouter::getInstance('site')->route() would still run into the same problems because you cannot pass additional constructor parameters into the getInstance() method for subclasses, all it knows how to handle is an options array. So going through that route, the only way to get the app and menu params for JRouterSite objects is through the constructor defaults, which right now is JApplication::getInstance('site') to get the app and $app->getMenu() to get the menu.

In our testing environment, it's really quite complex to make this all work right. There are too many dependencies that have to get set up right somewhere (either pushing router mocks into JRoute::$_router or JRouter::$instances or pushing application mocks into JApplicationCms::$instances at a minimum, then mocking the internals; though considering it's the JPagination tests we're talking about here as the primary failure point, those shouldn't be trying to validate "real" routing behaviors anyway).

The reason this has all been working fine up until the request we made was implemented (stop allowing a null client), as George hinted to, is because it has been possible to work with a null client value internal to JRoute::_() because $app-> getName() isn't mocked meaning you don't get a real response from that method, so the resulting call ends up as $app->getRouter(null) which returns a JRouter instance (the base class, not one of the application subclasses). Obviously this isn't the "right" behavior as in normal use of the CMS it should be pretty freakin' impossible to do that.

avatar laoneo
laoneo - comment - 4 Jul 2017

For me would be interesting to know if we want to introduce more static functions or try to work more with objects.

avatar mbabker
mbabker - comment - 18 Jul 2017

@izharaazmi Check izharaazmi#3 and merge it please. That should fix all the test issues.

avatar joomla-cms-bot joomla-cms-bot - change - 18 Jul 2017
Category Libraries Front End Plugins Libraries Front End Plugins Unit Tests
avatar mbabker
mbabker - comment - 29 Jul 2017

IMO this is good to merge. If we could get a couple tests here it would honestly be a pretty good improvement to have in 3.8.

avatar ggppdk
ggppdk - comment - 29 Jul 2017

... it would honestly be a pretty good improvement to have in 3.8.

After this is tested and merged the article manager can get a preview icon per row ...

Also a lot of 3rd party extensions developers will like this, and then their users too
Finally i will be able to replace the code that i am using now to genererate frontend SEF URLs in backend

I ll find time to test

avatar laoneo
laoneo - comment - 29 Jul 2017

The feature is really cool, but I really would like to see this implemented in a none static way.

avatar mbabker
mbabker - comment - 29 Jul 2017

We can look at transitioning JRoute to a non-static service at a later point. In the 3.x code unless you're in a handful of spots you're still going to have to go through a static global to do this, might as well consolidate it into one spot and in the 4.x code we can look at how to transform this into a proper OOP API.

avatar wilsonge
wilsonge - comment - 29 Jul 2017

but I really would like to see this implemented in a none static way

This is a static helper method for Router::build, nothing more, I don't see any real need for it to be non-static

I just did some testing of this. Nearly works but in the admin we need to enable sef urls otherwise i always end up with non-sef urls. I think moving this line https://github.com/joomla/joomla-cms/blob/staging/libraries/src/Joomla/CMS/Application/SiteApplication.php#L403 into the main CMSApplication class should do the trick :)

avatar mbabker
mbabker - comment - 29 Jul 2017

It's this line:

https://github.com/joomla/joomla-cms/blob/staging/libraries/src/Joomla/CMS/Application/SiteApplication.php#L403

That needs to be moved from the SiteApplication to the CMSApplication's getRouter method and should probably be tweaked to read this instead:

$options['mode'] = isset($options['mode']) ? $options['mode'] : \JFactory::getConfig()->get('sef');

Right now when you go through the admin app's getRouter method to get a site router, you won't get the correct SEF mode because we are only setting it for the site application. So as is you're only getting non SEF URLs for frontend content from the backend.

avatar joomla-cms-bot joomla-cms-bot - change - 9 Aug 2017
Category Libraries Front End Plugins Unit Tests Repository Unit Tests Administration com_admin SQL Postgresql MS SQL com_categories com_config com_content com_fields com_finder com_installer com_joomlaupdate com_languages
avatar izharaazmi
izharaazmi - comment - 9 Aug 2017

Sorry I didn't notice its still against 3.8-dev. I'll fix it.

avatar joomla-cms-bot joomla-cms-bot - change - 9 Aug 2017
Category Unit Tests Repository Administration com_admin SQL Postgresql MS SQL com_categories com_config com_content com_fields com_finder com_installer com_joomlaupdate com_languages Libraries Front End Plugins Unit Tests
avatar wilsonge
wilsonge - comment - 9 Aug 2017

Updated Pull Request location. Looks like there's a couple of extra conflicts as a result. But nearly there!!

avatar izharaazmi
izharaazmi - comment - 9 Aug 2017

Resolved the conflicts.

avatar izharaazmi
izharaazmi - comment - 9 Aug 2017

At this stage I would like to follow with @mbabker in #16879 (comment) and do the following changes:

  • Make real method stubs for JRoute::site() and JRoute::administrator() removing the magic method.
  • Make the link method protected to prevent having multiple syntax to do the same thing.

Please advise.

avatar wilsonge
wilsonge - comment - 9 Aug 2017

In my personal opinion as I'm currently building a new application api in Joomla 4, I'd rather remove the JRoute::site() and JRoute:: administrator() methods and if you're going cross site force people to use JRoute::link()

avatar izharaazmi
izharaazmi - comment - 9 Aug 2017

If I am not overthinking πŸ˜„ , are you doing something like removing strict references to site and administrator as the only supported applications?

...force people to use JRoute::link()

So, should I just remove the magic method and do not have these methods at all in the first place?

avatar wilsonge
wilsonge - comment - 9 Aug 2017

If I am not overthinking πŸ˜„ , are you doing something like removing strict references to site and administrator as the only supported applications?

Yes

So, should I just remove the magic method and do not have these methods at all in the first place?

In my opinion yes. See what @mbabker says

avatar izharaazmi izharaazmi - change - 9 Aug 2017
Labels Added: ?
avatar izharaazmi izharaazmi - change - 9 Aug 2017
The description was changed
avatar izharaazmi izharaazmi - edited - 9 Aug 2017
avatar izharaazmi
izharaazmi - comment - 13 Aug 2017

Can we get this in 3.8?

avatar mbabker
mbabker - comment - 13 Aug 2017

If this can get tested out no later than beta 3 then yes.

avatar tonypartridge
tonypartridge - comment - 14 Aug 2017

I'll try and get this tested. But would love to see it tested and added, planning a new feature to 'View' Menu Items from the backend which loads the link in a new window/tab and this would allow SEF Routing nicely.

avatar Fedik
Fedik - comment - 15 Aug 2017

quick test (with default test content):

JRoute::link('site', 'index.php?option=com_content&view=article&id=17');
=> /index.php?id=17 wrong (note: article does not have a menu item)

JRoute::link('site', 'index.php?option=com_content&view=article&id=6');
=> /index.php/single-article correct (note: article has a menu item)

JRoute::link('site', 'index.php?option=com_content&view=category&layout=blog&id=14');
=> /index.php/14-sample-data-articles?layout=blog seems correct

JRoute::link('site', 'index.php?option=com_content&view=category&layout=blog&id=27');
=> /index.php/article-category-blog correct

half working πŸ˜‰
But maybe it more an issue with the Content router than with this patch, hard to say.

avatar wilsonge
wilsonge - comment - 15 Aug 2017

But maybe it more an issue with the Content router than with this patch, hard to say.

It is I think. If you add the category id into the url then it should work ok :)

avatar mbabker
mbabker - comment - 15 Aug 2017

In theory that article ID 17 should still get a SEF URL unless all of its parent categories too have no menu item (or its only parent is a featured or archived view).

avatar izharaazmi
izharaazmi - comment - 15 Aug 2017

The sef_advanced mode is broken for com_content.

avatar Fedik Fedik - test_item - 15 Aug 2017 - Tested successfully
avatar Fedik
Fedik - comment - 15 Aug 2017

It is I think.

Yeap, I just tried default method JRoute::_( 'index.php?option=com_content&view=article&id=17'); at the site, and got same result.

As it do not related to the current patch, I am going to mark it as success.

avatar Fedik
Fedik - comment - 15 Aug 2017

I have tested this item βœ… successfully on b3136c4


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/16879.

avatar sanderpotjer sanderpotjer - test_item - 30 Aug 2017 - Tested successfully
avatar sanderpotjer
sanderpotjer - comment - 30 Aug 2017

I have tested this item βœ… successfully on b3136c4

@izharaazmi & @andrepereiradasilva great PR, have been using a hacky way so far to generate frontend SEF links from the backend, so much welcome :-)

I have been playing around with the patch, and for all links I tried the output was similar in the frontend as in the backend. Tried varies combinations, SEF on/off, htaccess on/off, stable/experimental router. So seems to work correctly!


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/16879.

avatar izharaazmi
izharaazmi - comment - 31 Aug 2017

@mbabker Its post beta4 now. Is there still any change getting this in?

avatar izharaazmi izharaazmi - change - 15 Sep 2017
Labels Removed: ?
avatar izharaazmi
izharaazmi - comment - 15 Sep 2017

Conflicts resolved.

avatar euismod2336 euismod2336 - test_item - 29 Sep 2017 - Tested successfully
avatar euismod2336
euismod2336 - comment - 29 Sep 2017

I have tested this item βœ… successfully on b3136c4

Love this PR.

Both in frontend as backend the expected url's show up, both with SEF enabled and disabled.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/16879.

avatar franz-wohlkoenig franz-wohlkoenig - change - 29 Sep 2017
Status Pending Ready to Commit
avatar franz-wohlkoenig
franz-wohlkoenig - comment - 29 Sep 2017

RTC after two successful tests.

avatar asfaqueali
asfaqueali - comment - 9 Feb 2018

I have tested this and really need this PR to be added in Joomla soon, It's been month how long do we have to wait. Please consider releasing this soon

avatar tonypartridge
tonypartridge - comment - 9 Feb 2018

@asfaqueali

Unfortunately this cannot be added into joomla! Until 3.9 since new features cannot go into 3.8 as that would break versioning.

avatar asfaqueali
asfaqueali - comment - 9 Feb 2018

@tonypartridge yeah I understand, but its been almost 4 months and release date of 3.9 is not defined so far.

avatar tonypartridge
tonypartridge - comment - 9 Feb 2018

It won’t be merged into 3.9 until 3.9 is ready to be merged to the staging branch.

@wilsonge is the 3.9 release lead I believe and won’t miss it out I’m sure.

On 9 Feb 2018, 07:51 +0000, Asfaque Ali Ansari notifications@github.com, wrote:

@tonypartridge yeah I understand, but its been almost 4 months and release date of 3.9 is not defined so far.
β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

avatar wilsonge wilsonge - change - 9 Mar 2018
Status Ready to Commit Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2018-03-09 02:21:45
Closed_By wilsonge
Labels Added: ?
avatar wilsonge wilsonge - close - 9 Mar 2018
avatar wilsonge wilsonge - merge - 9 Mar 2018
avatar wilsonge
wilsonge - comment - 9 Mar 2018

Merged - awesome work :)

avatar asfaqueali
asfaqueali - comment - 9 Mar 2018

@tonypartridge @wilsonge Thanks for merging it. @izharaazmi thanks for this commit.

avatar tonypartridge
tonypartridge - comment - 9 Mar 2018

Thanks George! I’ll try and get onto the view in site button next week for menu items

On 9 Mar 2018, 04:40 +0000, Asfaque Ali Ansari notifications@github.com, wrote:

@tonypartridge @wilsonge Thanks for merging it. @izharaazmi thanks for this commit.
β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

avatar bascherz
bascherz - comment - 2 May 2019

Hi guys,

I am not having a successful experience using the new JRoute::link method. It simply doesn't appear to work in my plugin at all. The code is below. The calls to link are commented-out because they simply don't do anything.

// Build article links
$rel_link = str_replace('/administrator','',JRoute::_(ContentHelperRoute::getArticleRoute($article->id,$article->catid)));
$abs_link = str_replace('/administrator','',JURI::base().$rel_link);
$abs_link = str_replace(':/','://',str_replace('//','/',$abs_link));
// $abs_link = JRoute::link('site',$abs_link);
// $rel_link = JRoute::link('site',$rel_link);

As you can see, I still have to remove the "administrator//" part of back end links and for back end links I still get no SEF URL out of JRoute::link. This particular plugin has a feature that allows either an absolute or relative link to be inserted into the template being used to email a notification that an article was just published or updated.

I'm hoping someone here can show me the err of my ways and, if applicable, point me to where I should have posted this comment.

Thanks,
Bruce

avatar franz-wohlkoenig
franz-wohlkoenig - comment - 2 May 2019

@bascherz please open a new Issue (link to this PR) as comments on closed Pull Requests didn't get much notice.

avatar tonypartridge
tonypartridge - comment - 2 May 2019

@bascherz - Your code is wrong, you are trying to JRoute a JRouted URL you cannot do that, you need to call the url non-routed i.e. with index.php?option=com_content etc. So try removing the JRoute::_() on the $rel_link = . Also you shouldn't need to replace administrator.

avatar wilsonge
wilsonge - comment - 2 May 2019

Documentation for this is available at https://docs.joomla.org/J3.x:Supporting_SEF_URLs_in_your_component#Creating_Frontend_SEF_URLs_in_the_Administrator as of approximately 5 minutes ago :)

avatar bascherz
bascherz - comment - 3 May 2019

Documentation for this is available at https://docs.joomla.org/J3.x:Supporting_SEF_URLs_in_your_component#Creating_Frontend_SEF_URLs_in_the_Administrator as of approximately 5 minutes ago :)

Somewhat a brute force method, but it does work. Some of my URLs are not SEF (for whatever reason) and that threw me off a bit as well. No need to open an issue @franz-wohlkoenig.

Here's the code now. Category ID apparently is not needed.

$rel_link = JRoute::link('site','index.php?option=com_content&view=article&id='.$article->id);
$abs_link = JURI::base().$rel_link;

Thanks everyone.

avatar wilsonge
wilsonge - comment - 4 May 2019

It's not required but probably helpful to get exactly the same url as the frontend

avatar infograf768
infograf768 - comment - 4 May 2019

Also missing language ;)

		if ($article->language && Multilanguage::isEnabled())
		{
			// Get the sef prefix for the language
			$query->clear()
				->select('sef')
				->from($db->quoteName('#__languages'))
				->where($db->quoteName('published') . '= 1')
				->where($db->quoteName('lang_code') . ' = ' . $db->quote($article->language));
			$db->setQuery($query);

			$sef = $db->loadResult();

			if ($article->language != '*')
			{
				$lang = '&lang=' . $sef;
			}
		}

Add a Comment

Login with GitHub to post a comment