public function forceDelete($id = null)
{
// Load the specified record (if necessary)
if (!empty($id)) {
$this->findOrFail($id);
}
$k = $this->getIdFieldName();
$pk = !$id ? $this->{$k} : $id;
// If no primary key is given, return false.
if (!$pk) {
throw new TreeUnexpectedPrimaryKey();
}
// Execute the logic only if I have a primary key, otherwise I could have weird results
// Perform the checks on the current node *BEFORE* starting to delete the children
try {
$this->triggerEvent('onBeforeDelete', array(&$pk));
} catch (\Exception $e) {
return false;
}
$result = true;
// Recursively delete all children nodes as long as we are not a leaf node
if (!$this->isLeaf()) {
// Get all sub-nodes
$table = $this->getClone();
$table->bind($this->getData());
$subNodes = $table->getDescendants();
// Delete all subnodes (goes through the model to trigger the observers)
if (!empty($subNodes)) {
/** @var TreeModel $item */
foreach ($subNodes as $item) {
// We have to pass the id, so we are getting it again from the database.
// We have to do in this way, since a previous child could have changed our lft and rgt values
if (!$item->forceDelete($item->{$k})) {
// A subnode failed or prevents the delete, continue deleting other nodes,
// but preserve the current node (ie the parent)
$result = false;
}
}
// Load it again, since while deleting a children we could have updated ourselves, too
$this->find($pk);
}
}
if ($result) {
$db = $this->getDbo();
// Delete the row by primary key.
$query = $db->getQuery(true);
$query->delete();
$query->from($this->getTableName());
$query->where($db->qn($this->getIdFieldName()) . ' = ' . $db->q($pk));
$db->setQuery($query)->execute();
$this->triggerEvent('onAfterDelete', array(&$pk));
}
return $this;
}