User tests: Successful: Unsuccessful:
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.
Status | New | ⇒ | Pending |
Labels |
Added:
?
|
@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:
6.5 ms
to ~4.7 ms
.15 ms
to ~9 ms
.30 ms
to ~19 ms
.78 ms
to ~38 ms
.232 ms
to ~76 ms
.730 ms
to ~155 ms
.This PR has received new commits.
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.
I have tested this item 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.
I have tested this PR unsuccessfully on df6acd2.
Simple test, I take default installation added 5 Menu Items:
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.
@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?
@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.
This PR has received new commits.
This PR has received new commits.
Please test this again. This should solve the previous issues.
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?
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);
@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.
ok i will check. thanks
@efEris i tried you solution and it worked. And without the getItems
. Good work.
How did i test:
Use the current php file (before this PR) and removed this line: https://github.com/joomla/joomla-cms/blob/staging/modules/mod_menu/helper.php#L85.
As you said, put your code in this line https://github.com/joomla/joomla-cms/blob/staging/modules/mod_menu/helper.php#L56, so it becomes
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.
Category | ⇒ | Libraries Modules |
@hackwar any comment on the proposed improvement from @efEris would be good to move this PR forward if we can
@Hackwar Another nudge so we can move this PR forward.
I don't know which one is @efEris. So far this PR is complete the way it is.
@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;
}`
This PR has received new commits.
I've added the change like you proposed @HLeithner.
This PR has received new commits.
One thing, adding ", m.lft, m.rgt" to the query is no longer necessary.
This PR has received new commits.
One thing, adding ", m.lft, m.rgt" to the query is no longer necessary.
I have tested this item
as comment above
Category | Libraries Modules | ⇒ | Libraries Front End Modules |
I have tested this item
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 issue has two successful tests.
Status | Pending | ⇒ | Ready to Commit |
RTC
Labels |
Added:
?
|
Milestone |
Added: |
||
Labels |
Removed:
?
|
Labels |
Added:
?
|
Milestone changed to 3.7 as it is now not planned to have a 3.6.4 release
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 |
Labels |
Removed:
?
|
I have tested this item unsuccessfully on 51de1eb
I get this php notices:
This comment was created with the J!Tracker Application at issues.joomla.org/joomla-cms/8863.