J3 Issue ?
avatar aDaneInSpain
aDaneInSpain
26 Feb 2018

This was a pretty difficult bug to track down.

Steps to reproduce the issue

  1. Create a component with two identical view names in the manifest. Or download this sample component. com_test-1.0.0.zip
  2. Verify what menu items you have
  3. Install the component
  4. Verify that some menu items have been deleted (bug)
  5. Uninstall the component
  6. Verify that the root menu item has been deleted

Expected result

Menu item table is as before install and uninstall of the component.

Actual result

  • Default menu item is deleted and an error is shown when uninstalling the component.
  • Also the menu item id 2 and 3 are deleted when installing the component.
  • When attempting to install any other component thereafter the error Joomla\CMS\Table\Menu::_getNode(1, ) failed. is shown.

System information (as much as possible)

Joomla 3.8.3

before_installation

after_installation

after_uninstall

Additional comments

I believe this issue is related with #7199 #6778 and issues reported on other extension developer like this one: https://www.regularlabs.com/forum/extensionmanager/27388-impossible-to-install

avatar aDaneInSpain aDaneInSpain - open - 26 Feb 2018
avatar joomla-cms-bot joomla-cms-bot - change - 26 Feb 2018
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 26 Feb 2018
avatar franz-wohlkoenig franz-wohlkoenig - change - 26 Feb 2018
Category Components
avatar brianteeman
brianteeman - comment - 5 Mar 2018

Tried to install your test component and it failed to install with the following

Warning
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '??SHOW FULL COLUMNS FROM bb5yp_test_items WHERE Field LIKE 'id'??' at line 1
×
Error
Error installing component

avatar brianteeman
brianteeman - comment - 5 Mar 2018

update - it installs when i switch to NOT use the PDO driver

avatar brianteeman
brianteeman - comment - 5 Mar 2018

I can confirm this bug

avatar aDaneInSpain
aDaneInSpain - comment - 5 Mar 2018

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax;

The component was made using Component Creator. Do you think this is a general Component Creator bug or a Joomla one or a PDO one. Should we look into it, I guess is my question?

avatar brianteeman
brianteeman - comment - 5 Mar 2018

probably a CC issue

avatar franz-wohlkoenig franz-wohlkoenig - change - 5 Mar 2018
Status New Discussion
avatar brianteeman brianteeman - change - 25 Mar 2018
Labels Added: J3 Issue
avatar brianteeman brianteeman - labeled - 25 Mar 2018
avatar jmeStark
jmeStark - comment - 16 May 2018

Hello,

I have been researching about this issue and i saw that joomla execute a delete command in the menu table where the only filter fields are lft and rgt. e.g: delete from #__menu where rgt between 2 and 5. This sql deletes some menu rows that they are not relationed with the extension is being installed. This could be seen activating mysql redo log and installing this extension. How can you see this:
1.I did a backup of menu table.
2. I installed the extension.
3. I recover the backup done in step 1.
4. I searched into redo log for delete on manu table. Delete #__menu where XXXX.
5. I executed a select sql: select * from #__menu where XXXX. This sql showed me the rows deleted, and they didn't belong to the installed extension.

May be the lft and rgt fields setted when the extension is being installed are wrong. May be the delete query should not be executed when installing an extension. May be there is needed add to where the primary key to the where.

best regards,
José M.

avatar Bakual
Bakual - comment - 16 May 2018

@jmeStark That sounds like you have a corrupt nested set table there. Because lft and rgt should indeed mark the "end" of the component specific menu tree.

Of course, using backup and restore will break your menu table if you installed an extension between. lft and rgt values change almost always as soon as you manipulate any menuitem.

avatar aDaneInSpain
aDaneInSpain - comment - 16 May 2018

@Bakual Did you read the initial bug report? What @jmeStark is experiencing is consistent with this bug. It is replicable in a vanilla Joomla installation.

avatar Bakual
Bakual - comment - 16 May 2018

I've read it, yes. I just thought it may be a different case which emerged due to restoring single table backups (which wont work well).

As for your description, the second image shows indeed also a wrong nested set. The level, lft and rgt values are wrong for com_test. Level should be 1, lft should be at least 1 as well, never 0.
So to me it looks like the issue isn't happening when deleting, instead it happens when creating the menuitems.

I haven't debugged it with your test component. Just from reading here. Maybe that helps someone else find the source.

avatar aDaneInSpain
aDaneInSpain - comment - 16 May 2018

Yes. As reported it starts breaking when installing the component but mostly have a huge impact on the user when uninstalling.

avatar Bakual
Bakual - comment - 16 May 2018

The issue comes indeed from your duplicated menuitem. The installer tries to create the duplicate and it fails because the alias is already present.
This fail now triggers a code block to deal with that:

if (!$table->bind($data) || !$table->check() || !$table->store())
{
// The menu item already exists. Delete it and retry instead of throwing an error.
$query = $db->getQuery(true)
->select('id')
->from('#__menu')
->where('menutype = ' . $db->q($data['menutype']))
->where('client_id = 1')
->where('link = ' . $db->q($data['link']))
->where('type = ' . $db->q($data['type']))
->where('parent_id = ' . $db->q($data['parent_id']))
->where('home = ' . $db->q($data['home']));
$db->setQuery($query);
$menu_id = $db->loadResult();
if (!$menu_id)
{
// Oops! Could not get the menu ID. Go back and rollback changes.
\JError::raiseWarning(1, $table->getError());
return false;
}
else
{
/** @var \JTableMenu $temporaryTable */
$temporaryTable = Table::getInstance('menu');
$temporaryTable->delete($menu_id, true);
$temporaryTable->rebuild($data['parent_id']);
// Retry creating the menu item
$table->setLocation($parentId, 'last-child');
if (!$table->bind($data) || !$table->check() || !$table->store())
{
// Install failed, warn user and rollback changes
\JError::raiseWarning(1, $table->getError());
return false;
}
}
}

Basically it deletes the existing menuitem and tries to recreate the previously failed one.
The bug is on line
$temporaryTable->rebuild($data['parent_id']);
where it rebuilds the nested set after the deleting of the existing menuitem.
I don't have time atm to try further but I guess it may work if one passes the lft argument to that rebuild method. As it is, the method rebuilds the set and puts the items to lft=0, which is wrong.

So there is a bug in the installer, but you will still not be able to have two identical named menuitems. Rename your duplicated menuitem to another name and it should work.

avatar aDaneInSpain
aDaneInSpain - comment - 16 May 2018

Nice work. I agree it should not be possible to have two identical view names, but it should not create this much havoc with your installation. I propose that the installer simply fails if there are two identical menu views in the extension?

avatar Bakual
Bakual - comment - 16 May 2018

I'd rather fix the rebuild call ?

avatar Bakual
Bakual - comment - 17 May 2018

Please test #20436

avatar Bakual
Bakual - comment - 17 May 2018

Closing as we have a PR.

avatar Bakual Bakual - change - 17 May 2018
Status Discussion Closed
Closed_Date 0000-00-00 00:00:00 2018-05-17 07:56:05
Closed_By Bakual
avatar Bakual Bakual - close - 17 May 2018

Add a Comment

Login with GitHub to post a comment