How to delete an MPTT Node
03 Sep 2006
If you use MPTT tables anywhere (The cake acl system uses it) you may have found that when you delete an entry, the lft and rght fields for the neighouring nodes don't get updated. This may have rather dire concequences ;)
There is an open ticket for how to delete from the cake acl tables, but as it is potentially quite generic, I thought I'd include the (potential) fix here. Below are two versions of a delete method, one takes care of associations, and the other doesn't:
// If there are associations to take care of
function
delete($Alias) {
$class = $this->name;
$result = $this->findByAlias($Alias);
$object =
$result[$class];
if ($object == null || count($object) == 0) {
return false;
}
$idList[] = $result[$class]['id'];
// won't somebody please think of the children.
$Children=
$this->findAll(array("rght"=>"< {$result[$class]['rght']}","lft"=>"> {$result[$class]['lft']}"),"id",null,null,null,-1);
foreach($Children as $Child) {
$idList[] = $Child[$class]['id'];
}
// Delete associated
permissions.
$this->ArosAco->query("DELETE FROM ".$this->ArosAco->tablePrefix.$this->ArosAco->table." WHERE
{$class}_id in (".implode(",",$idList).")");
// Perform the delete
$table =
$this->tablePrefix.$this->table;
$this->query("DELETE FROM $table WHERE $table.lft >= {$result[$class]['lft']} AND
$table.rght <= {$result[$class]['rght']}");
// Reindex.
$shift = 1+ $result[$class]['rght'] -
$result[$class]['lft'];
$this->query('UPDATE ' . $table . ' SET `rght` = `rght` - ' . $shift . ' WHERE `rght` > '
. $result[$class]['rght']);
$this->query('UPDATE ' . $table . ' SET `lft` = `lft` - ' . $shift . ' WHERE `lft`
> ' . $result[$class]['lft']);
return true;
}
// No associations to take care or
function delete($id)
{
$result = $this-read();
// Perform the delete
$table = $this->tablePrefix.$this->table;
$this->query("DELETE FROM $table WHERE $table.lft >= {$result[$class]['lft']} AND $table.rght <=
{$result[$class]['rght']}");
// Reindex.
$shift = 1+ $result[$class]['rght'] - $result[$class]['lft'];
$this->query('UPDATE ' . $table . ' SET `rght` = `rght` - ' . $shift . ' WHERE `rght` > ' .
$result[$class]['rght']);
$this->query('UPDATE ' . $table . ' SET `lft` = `lft` - ' . $shift . ' WHERE `lft` > ' .
$result[$class]['lft']);
return true;
}
// If there are associations to take care offunctiondelete($Alias) {$class = $this->name;$result = $this->findByAlias($Alias);$object =$result[$class];if ($object == null || count($object) == 0) {return false;}$idList[] = $result[$class]['id'];// won't somebody please think of the children.$Children=$this->findAll(array("rght"=>"< {$result[$class]['rght']}","lft"=>"> {$result[$class]['lft']}"),"id",null,null,null,-1);foreach($Children as $Child) {$idList[] = $Child[$class]['id'];}// Delete associatedpermissions.$this->ArosAco->query("DELETE FROM ".$this->ArosAco->tablePrefix.$this->ArosAco->table." WHERE{$class}_id in (".implode(",",$idList).")");// Perform the delete$table =$this->tablePrefix.$this->table;$this->query("DELETE FROM $table WHERE $table.lft >= {$result[$class]['lft']} AND$table.rght <= {$result[$class]['rght']}");// Reindex.$shift = 1+ $result[$class]['rght'] -$result[$class]['lft'];$this->query('UPDATE ' . $table . ' SET `rght` = `rght` - ' . $shift . ' WHERE `rght` > '. $result[$class]['rght']);$this->query('UPDATE ' . $table . ' SET `lft` = `lft` - ' . $shift . ' WHERE `lft`> ' . $result[$class]['lft']);return true;}// No associations to take care orfunction delete($id){$result = $this-read();// Perform the delete$table = $this->tablePrefix.$this->table;$this->query("DELETE FROM $table WHERE $table.lft >= {$result[$class]['lft']} AND $table.rght <={$result[$class]['rght']}");// Reindex.$shift = 1+ $result[$class]['rght'] - $result[$class]['lft'];$this->query('UPDATE ' . $table . ' SET `rght` = `rght` - ' . $shift . ' WHERE `rght` > ' .$result[$class]['rght']);$this->query('UPDATE ' . $table . ' SET `lft` = `lft` - ' . $shift . ' WHERE `lft` > ' .$result[$class]['lft']);return true;}
Should anybody use this and find it causes a problem please let me know.
Andy, on 1/1/70