/**
* Method to delete a node and, optionally, its child nodes from the table.
*
* @param integer $pk The primary key of the node to delete.
* @param boolean $children True to delete child nodes, false to move them up a level.
*
* @return boolean True on success.
*
* @since 1.7.0
*/
public function delete($pk = null, $children = true)
{
$k = $this->_tbl_key;
$pk = \is_null($pk) ? $this->{$k} : $pk;
// Pre-processing by observers
$event = new Event('onBeforeDelete', ['pk' => $pk]);
$this->getDispatcher()->dispatch('onBeforeDelete', $event);
// If tracking assets, remove the asset first.
if ($this->_trackAssets) {
$name = $this->_getAssetName();
/** @var Asset $asset */
$asset = Table::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo()));
if ($asset->loadByName($name)) {
// Delete the node in assets table.
if (!$asset->delete(null, $children)) {
$this->setError($asset->getError());
return false;
}
} else {
$this->setError($asset->getError());
return false;
}
}
// Lock the table for writing.
if (!$this->_lock()) {
// Error message set in lock method.
return false;
}
// Get the node by id.
$node = $this->_getNode($pk);
if (empty($node)) {
// Error message set in getNode method.
$this->_unlock();
return false;
}
$query = $this->_db->getQuery(true);
// Should we delete all children along with the node?
if ($children) {
// Delete the node and all of its children.
$query->clear()->delete($this->_tbl)->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Compress the left values.
$query->clear()->update($this->_tbl)->set('lft = lft - ' . (int) $node->width)->where('lft > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Compress the right values.
$query->clear()->update($this->_tbl)->set('rgt = rgt - ' . (int) $node->width)->where('rgt > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
} else {
// 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');
}
// Unlock the table for writing.
$this->_unlock();
// Post-processing by observers
$event = new Event('onAfterDelete', ['pk' => $pk]);
$this->getDispatcher()->dispatch('onAfterDelete', $event);
return true;
}