? Success

User tests: Successful: Unsuccessful:

avatar Hackwar
Hackwar
8 Jan 2016

mod_menu checks for every menu item if the item is a parent of another menu item. The method to do that via $menu->getItems() is pretty expensive and can create great delays on bigger sites. The proposed code will reduce this immensely by only checking those menu items that can have a child due to lft and rgt differing by more than one. Unfortunately that will not automatically mean that a menu item actually has children, since children could be present, but unpublished or in a different language. In those cases lft and rgt differ, but there is no child item anyway.

This will not change existing sites, but will mean a performance improvement. So the best way to test this would be to compare execution times on sites with a lot of menu items (>500). Another way would be a code review by a maintainer. 😄

This came up because of the insistence of @volandku in the Joomla IRC channel on Freenode who made me look into this. Thank you for being persistent. 😄

avatar Hackwar Hackwar - open - 8 Jan 2016
avatar Hackwar Hackwar - change - 8 Jan 2016
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 8 Jan 2016
Labels Added: ?
avatar andrepereiradasilva andrepereiradasilva - test_item - 9 Jan 2016 - Tested unsuccessfully
avatar andrepereiradasilva
andrepereiradasilva - comment - 9 Jan 2016

I have tested this item :red_circle: unsuccessfully on 51de1eb

I get this php notices:

Notice: Undefined property: stdClass::$rgt in /path/to/joomla-cms/modules/mod_menu/helper.php on line 77
Notice: Undefined property: stdClass::$lft in /path/to/joomla-cms/modules/mod_menu/helper.php on line 77


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

avatar andrepereiradasilva
andrepereiradasilva - comment - 9 Jan 2016

@Hackwar, instead of doing this:

foreach ($items as $i => $item)
{
    /* Code removed for simplifying */
    $item->deeper     = false;
    $item->shallower  = false;
    $item->level_diff = 0;

    if (isset($items[$lastitem]))
    {
        $items[$lastitem]->deeper     = ($item->level > $items[$lastitem]->level);
        $items[$lastitem]->shallower  = ($item->level < $items[$lastitem]->level);
        $items[$lastitem]->level_diff = ($items[$lastitem]->level - $item->level);
    }

    $item->parent = (boolean) ($item->rgt > $item->lft + 1) && $menu->getItems('parent_id', (int) $item->id, true);
    /* Code removed for simplifying */
}

if (isset($items[$lastitem]))
{
    $items[$lastitem]->deeper     = (($start?$start:1) > $items[$lastitem]->level);
    $items[$lastitem]->shallower  = (($start?$start:1) < $items[$lastitem]->level);
    $items[$lastitem]->level_diff = ($items[$lastitem]->level - ($start?$start:1));
}

Can't we do something like this?:

foreach ($items as $i => $item)
{
    /* Code removed for simplifying */
    $item->deeper     = false;
    $item->shallower  = false;
    $item->level_diff = 0;
    $item->parent     = 0;

    if (isset($items[$lastitem]))
    {
        $items[$lastitem]->deeper     = ($item->level > $items[$lastitem]->level);
        $items[$lastitem]->shallower  = ($item->level < $items[$lastitem]->level);
        $items[$lastitem]->level_diff = ($items[$lastitem]->level - $item->level);
        $items[$lastitem]->parent     = ($items[$lastitem]->level_diff == -1);
    }
    /* Code removed for simplifying */
}

if (isset($items[$lastitem]))
{
    $items[$lastitem]->deeper     = (($start?$start:1) > $items[$lastitem]->level);
    $items[$lastitem]->shallower  = (($start?$start:1) < $items[$lastitem]->level);
    $items[$lastitem]->level_diff = ($items[$lastitem]->level - ($start?$start:1));
    $items[$lastitem]->parent     = ($items[$lastitem]->level_diff == -1);
}

In other words, can't we just don't use the getItems to calculate if current menu item is a parent or not and use the already calculated level_diff to do that.

If we can do that we get even further performance improvements.

I run a test with a menu with several levels (thank for batch processing :)) and the for cycle got from:

  • 25 published items: ~6.5 ms to ~4.7 ms.
  • 50 published items: ~15 ms to ~9 ms.
  • 100 published items: ~30 ms to ~19 ms.
  • 200 published items: ~78 ms to ~38 ms.
  • 400 published items: ~232 ms to ~76 ms.
  • 800 published items: ~730 ms to ~155 ms.
  • and so on ...
avatar joomla-cms-bot
joomla-cms-bot - comment - 9 Jan 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar Hackwar
Hackwar - comment - 9 Jan 2016

First of all, sorry for the broken code. Yes, you are right, your proposal is even better. I added your code. I'm setting the parent to false by default to have it set at all times.

avatar andrepereiradasilva andrepereiradasilva - test_item - 9 Jan 2016 - Tested successfully
avatar andrepereiradasilva
andrepereiradasilva - comment - 9 Jan 2016

I have tested this item :white_check_mark: successfully on df6acd2

Thank you for find that needed performance optimization.
This can have some performance impact on sites with a lot of menu items.

Correct me if i'm wrong but the last element can't be the parent of anything, since it's the last.
That is why you didn't put the $items[$lastitem]->parent = ($items[$lastitem]->level_diff == -1); in the setting of last item after the for cycle as i suggested.
Makes sense.


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

avatar efEris
efEris - comment - 21 Jan 2016

I have tested this PR :red_circle: unsuccessfully on df6acd2.

Simple test, I take default installation added 5 Menu Items:

  • Item 1
    • Item 1a
  • Item 2
    • Item 2a
      • Item 2b

Module with "Show Sub-menu Items" off shows on active "Item 1" a difference at the last item, in this case "Item 2".

Without patch: parent = true
With patch: parent = false

If "Show Sub-menu Items" is on the "Item 2" parent value is correct (true).

Also if "Show Sub-menu Items" is on the the complete testcase is correct.

avatar andrepereiradasilva
andrepereiradasilva - comment - 26 Jan 2016

@efEris we know the last item parent value can be not ok. See my comment when i tested.

Correct me if i'm wrong but the last element can't be the parent of anything, since it's the last.
That is why you didn't put the $items[$lastitem]->parent = ($items[$lastitem]->level_diff == -1); in the setting of last item after the for cycle as i suggested.
Makes sense.

But in what that affected your test? Did the menu not appeared correctly?

avatar efEris
efEris - comment - 26 Jan 2016

@andrepereiradasilva sure because the li-tag for the last element doesn't get the "parent" class, that could lead to a visual problem if you use this class (the only way) to mark the link as parent item.

avatar andrepereiradasilva
andrepereiradasilva - comment - 26 Jan 2016

Ok, let's wait for @Hackwar to solve that.

avatar joomla-cms-bot
joomla-cms-bot - comment - 27 Jan 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar joomla-cms-bot
joomla-cms-bot - comment - 27 Jan 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar Hackwar
Hackwar - comment - 27 Jan 2016

Please test this again. This should solve the previous issues.

avatar efEris
efEris - comment - 28 Jan 2016

Hi,

while testing this I think I came to a better solution.

Add this to the beginning of the foreach loop before filtering the unseen items.

$item->parent = false;
if (isset($items[$lastitem])
  && $items[$lastitem]->id == $item->parent_id)
{
  $items[$lastitem]->parent = true;
}

btw. is it normal that the joomla patch tester overrides the complete file with a incompatible version?

avatar andrepereiradasilva
andrepereiradasilva - comment - 28 Jan 2016

I think the prior solution (before revert) works, if you add this line inside the if after the for cycle (https://github.com/Hackwar/joomla-cms/blob/df6acd259cb3062ad0ec1b1499f72aa6cea3e10e/modules/mod_menu/helper.php#-L126-L131) to set the last parent:

$items[$lastitem]->parent     = ($items[$lastitem]->level_diff == -1);
avatar efEris
efEris - comment - 28 Jan 2016

@andrepereiradasilva I tested this first, but no that will not work because we don't have the child at this point. if you can please try my solution.

avatar andrepereiradasilva
andrepereiradasilva - comment - 28 Jan 2016

ok i will check. thanks

avatar andrepereiradasilva
andrepereiradasilva - comment - 28 Jan 2016

@efEris i tried you solution and it worked. And without the getItems. Good work.

How did i test:

foreach ($items as $i => $item)
{
    $item->parent = false;
    if (isset($items[$lastitem]) && $items[$lastitem]->id == $item->parent_id)
    {
        $items[$lastitem]->parent = true;
    }
    // code removed for brevity
}

@Hackwar can you check? With @efEris solution i think we can get rid of getItems and with that improving performance even further.

avatar brianteeman brianteeman - change - 1 Mar 2016
Category Libraries Modules
avatar brianteeman
brianteeman - comment - 12 Apr 2016

@hackwar any comment on the proposed improvement from @efEris would be good to move this PR forward if we can


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

avatar roland-d
roland-d - comment - 24 Jun 2016

@Hackwar Another nudge so we can move this PR forward.


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

avatar Hackwar
Hackwar - comment - 25 Jun 2016

I don't know which one is @efEris. So far this PR is complete the way it is.

avatar HLeithner
HLeithner - comment - 27 Jun 2016

@Hackwar sorry I renamed the github Username

Instead of trying to get the ->parent value based on the level_diff its better to set it at the beginning before we delete the information.

Add the following code to the beginning of the foreach loop at Line 57, see comment from @andrepereiradasilva

    $item->parent = false;
    if (isset($items[$lastitem]) && $items[$lastitem]->id == $item->parent_id)
    {
        $items[$lastitem]->parent = true;
    }`
avatar joomla-cms-bot
joomla-cms-bot - comment - 28 Jun 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar Hackwar
Hackwar - comment - 28 Jun 2016

I've added the change like you proposed @HLeithner.

avatar joomla-cms-bot
joomla-cms-bot - comment - 28 Jun 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar HLeithner
HLeithner - comment - 28 Jun 2016

One thing, adding ", m.lft, m.rgt" to the query is no longer necessary.

avatar joomla-cms-bot
joomla-cms-bot - comment - 29 Jun 2016

This PR has received new commits.

CC: @andrepereiradasilva


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

avatar andrepereiradasilva
andrepereiradasilva - comment - 29 Jun 2016

One thing, adding ", m.lft, m.rgt" to the query is no longer necessary.

avatar andrepereiradasilva andrepereiradasilva - test_item - 23 Aug 2016 - Tested successfully
avatar andrepereiradasilva
andrepereiradasilva - comment - 23 Aug 2016

Menu with 500+ items

Before patch
image

After patch
image

So aprox. half the time

avatar andrepereiradasilva
andrepereiradasilva - comment - 23 Aug 2016

I have tested this item ✅ successfully on f1aa5a6

as comment above


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

avatar joomla-cms-bot joomla-cms-bot - change - 6 Sep 2016
Category Libraries Modules Libraries Front End Modules
avatar gwsdesk gwsdesk - test_item - 6 Sep 2016 - Tested successfully
avatar gwsdesk
gwsdesk - comment - 6 Sep 2016

I have tested this item ✅ successfully on c4d5c8c

I have tested this on a stock Joomla distro (3.6.3) will "Learning Sample data" in 4 languages and it has a visible faster loading time compared to pre-patch


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

avatar laoneo
laoneo - comment - 7 Sep 2016

This issue has two successful tests.


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

avatar wilsonge wilsonge - change - 5 Oct 2016
Status Pending Ready to Commit
avatar wilsonge
wilsonge - comment - 5 Oct 2016

RTC


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

avatar joomla-cms-bot joomla-cms-bot - change - 5 Oct 2016
Labels Added: ?
avatar wilsonge wilsonge - change - 5 Oct 2016
Milestone Added:
Labels Removed: ?
avatar wilsonge wilsonge - change - 5 Oct 2016
Labels Added: ?
avatar brianteeman
brianteeman - comment - 17 Oct 2016

Milestone changed to 3.7 as it is now not planned to have a 3.6.4 release

avatar rdeutz rdeutz - change - 18 Oct 2016
Status Ready to Commit Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2016-10-18 17:21:25
Closed_By rdeutz
avatar rdeutz rdeutz - close - 18 Oct 2016
avatar rdeutz rdeutz - merge - 18 Oct 2016
avatar brianteeman brianteeman - close - 18 Oct 2016
avatar brianteeman brianteeman - change - 18 Oct 2016
Labels Removed: ?

Add a Comment

Login with GitHub to post a comment