Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removing menu children on component install can destroy the whole menu tree #18404

Merged
merged 1 commit into from
Nov 1, 2017

Conversation

klas
Copy link
Contributor

@klas klas commented Oct 24, 2017

Menu table inherits Nested and since delete without second argument set to false, removes node and its children. As all child ids that need to be removed are already collected in previous step this means:
a) errors are generated if tree is consistent - all children are already removed in first delete, so all following deletes fail
b) with inconsistent trees this can delete random ranges of menus as delete only looks at lft-rgt values. This is not a unusual scenario as admin menus were previously not checked for consistency - I just had the whole menu wiped out due to faulty record.

To prevent this I propose that we delete only explicit records as I assume was also originally intended due to ids collection in previous step.

Summary of Changes

Set Children parameter to false in delete

Testing Instructions

Copy existing record from menu tree from one of installed 3rd party components (needs to be installable, not core) to create a faulty record: : copy existing record, change parent to non-existing id and set lft to 0 and rgt to 99999. It needs to be an admin menu (client = 1 ).

Update(reinstall) component with faulty record.

Expected result

Record disapears, the rest of the records remain.

Actual result

All records are erased.

Documentation Changes Required

Menu table inherits Nested and since delete without second argument set to false, removes node and its children. As all child ids that need to be removed are already collected in previous step this means:
a) errors are generated if three is consistent - all children are already removed in first delete, so all following deletes fail
b) with inconsistent threes this can delete random ranges of menus as delete only looks at lft-rgt values. This is not a unusual scenario as admin menus were previously not checked for consistency - I just had the whole menu wiped out due to faulty record.

To prevent this I propose that we delete only explicit records as I assume was also originally intended due to ids collection in previous step.
@klas klas changed the title Removing children can destroy the whole menu tree Removing menu children on component install can destroy the whole menu tree Oct 24, 2017
@csthomas
Copy link
Contributor

It helps because it do not need to delete children, which are already checked.

But it still leaves a mess after call this:

// Delete the node.
$query->clear()
->delete($this->_tbl)
->where('lft = ' . (int) $node->lft);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all node's children up a level.
$query->clear()
->update($this->_tbl)
->set('lft = lft - 1')
->set('rgt = rgt - 1')
->set('level = level - 1')
->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Adjust all the parent values for direct children of the deleted node.
$query->clear()
->update($this->_tbl)
->set('parent_id = ' . (int) $node->parent_id)
->where('parent_id = ' . (int) $node->$k);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all of the left values that are right of the node.
$query->clear()
->update($this->_tbl)
->set('lft = lft - 2')
->where('lft > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all of the right values that are right of the node.
$query->clear()
->update($this->_tbl)
->set('rgt = rgt - 2')
->where('rgt > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');

@csthomas
Copy link
Contributor

I have tested this item ✅ successfully on 904d02b

Code review.

Besides my doubts (above) but there is no better solution now. I mark it as success.


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

@alikon
Copy link
Contributor

alikon commented Oct 27, 2017

@csthomas open a new issue for that

@alikon
Copy link
Contributor

alikon commented Oct 27, 2017

I have tested this item ✅ successfully on 904d02b


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

@ghost
Copy link

ghost commented Oct 27, 2017

RTC after two successful tests.

@joomla-cms-bot joomla-cms-bot added the RTC This Pull Request is Ready To Commit label Oct 27, 2017
@izharaazmi
Copy link
Contributor

@alikon @csthomas What happens to the children after we delete a parent node, with this PR?

@csthomas
Copy link
Contributor

It depends how much is your database table corrupted.

  1. If there is no errors then there should not be any children because all menu items of the component are deleted, one by one.

  2. Otherwise, for example, if the values of column lft and rgt are corrupted for items X and Y that are contained (based on lft and rgt values) in item Z and you want to delete Z, then X and Y will be move one level up, lft and rgt will be updated, [X,Y].parent_id = Z.parent_id. This is the good side. The bad side is, when you delete corrupted item, you could move others menu items to one level up and other menu items may start be corrupted too.

If you want to read the code then take a look at code that I pasted above, joomla-cms/libraries/src/Table/Nested.php line 625.

Such operation, delete, runs a few sql queries in non atomic operation, executed separately and based on lft column, which is not unique in database tables.

@mbabker mbabker added this to the Joomla 3.8.2 milestone Nov 1, 2017
@mbabker mbabker merged commit c546f07 into joomla:staging Nov 1, 2017
@joomla-cms-bot joomla-cms-bot added PR-staging and removed RTC This Pull Request is Ready To Commit labels Nov 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants