Практика NestedSets - класс PHP управления деревьями Nested Sets, (дополнение)
Введение
Сам класс мы создали в предыдущей статье, но он позволяет только выбирать данные, но не изменять их. Поэтому напишем дополнительные методы.
По структуре и принципу класс такой же как и модуль Perl, единственные отличия в операторах и специфицеских особенностях языка. Итак, функции, которые мы включим в класс:
InsertUnit - создание узла;
DeleteUnit - удаление узла и подчиненных;
SetUnitUnder - перемещение узла в подчинение другому;
SetUnitNear - перемещение узла рядом с другим;
SetUnitLevel - изменение уровня узла (одни уровень вверх(вниз));
SetUnitOrder - изменение порядка узла в пределах подчинения;
_move_unit - внутренняя процедура перемещения узла и подчиненных;
Схемы и принципы описаны в предыдущих статьях, поэтому можно смело начинать писать код...
1. Создание (вставка) узла
PHP код (1)
// Создание узла
function InsertUnit ($under = 'root', $tree = 1, $order) {
if (!is_numeric($under)) {$under = 'root';}
if (!is_numeric($tree)) {$tree = 1;}
if ($under == 'root') {
$level = 1;
if ((isset($order) && $order == 'top') || $this->order == 'T') {
$key = 1;
} else {
$sql = 'SELECT MAX('.$this->right.') + 1 AS nums
FROM '.$this->table.
($this->type == 'M' ? ' WHERE '.$this->multi.' = '.$tree : '');
if (($query = mysql_query($sql)) &&
(mysql_num_rows($query) == 1) &&
($Data = mysql_fetch_array($query))) {$key = $Data['nums'];}
else {$key = 1;}
}
} else {
$sql = 'SELECT '.$this->left.' AS lk, '.
$this->right.' AS rk, '.
$this->level.'AS lv'.
($this->type == 'M' ? ', '.$this->multi.' AS cl ' : '').
' FROM '.$this->table.' WHERE '.$this->id.' = '.$under;
if (($mysql_query = mysql_query($sql)) &&
(mysql_num_rows($mysql_query) == 1) &&
($Data = mysql_fetch_array($mysql_query))) {
$level = $Data['lv'] + 1;
if ($this->type == 'M') {$tree = $Data['cl'];}
if ((isset($order) && $order == 'top') || $this->order == 'T') {
$key = $Data['cl'];
}
} else {trigger_error('ERR! Неправильный ID родительского узла!');}
}
$update = 'UPDATE '.$this->table.' SET '.
$this->right.' = '.$this->right.' + 2, '.
$this->left.' = CASE WHEN '.$this->left.' >= '.$key.
' THEN '.$this->left.' + 2
ELSE '.$this->left.' END
WHERE '.$this->right.' >= '.$key.
($this->type == 'M' ? ' AND '.$this->multi.' = '.$tree : '');
mysql_query($update);
// Список полей
$update = 'INSERT INTO '.$this->table.
' ('.$this->left.', '.
$this->right.', '.
$this->level.
($this->type == 'M' ? ', '.$this->multi : '').
') VAUES ('.$key.', '.($key + 1).', '.$level.
($this->type == 'M' ? ', '.$tree.')' : ')');
// Выполняем запрос
mysql_query($update);
// Получаем идентификатор вставленного узла
$sql = 'SELECT MAX('.$this->id.') FROM '.$this->table;
$mysql_query = mysql_query($sql);
$id = mysql_fetch_array($mysql_query);
return $id[0];
}
2. Удаление узла
PHP код (2)
// Удаление узла
function DeleteUnit ($unit) {
if (isset($unit)) {$this->SelectUnit($unit);}
$skew_tree = $this->unit['right'] - $this->unit['left'] + 1;
$update = 'DELETE FROM '.$this->table.'
WHERE '.$this->left.'>='.$this->unit['left'].' AND '.
$this->right.'<='.$this->unit['right'].
($this->type == 'M' ? ' AND '.$this->multi.'='.$this->unit['multi'] : '');
mysql_query($update);
$update = 'UPDATE '.$this->table.'
SET '.$this->left.'= CASE WHEN '.$this->left.'>'.$this->unit['left'].'
THEN '.$this->left.'-'.$skew_tree.'
ELSE '.$this->left.' END, '.
$this->right.'='.$this->right.'-'.$skew_tree.
' WHERE '.$this->right.'>'.$this->unit['right'].
($this->type == 'M' ? ' AND '.$this->multi.'='.$this->unit['multi'] : '');
mysql_query($update);
return 1;
}
3. Перемещение узла
Процедуры перемещения узла начнем со стандартной, точнее, универсальной, которая, собственно, узлы и перемещает остальные процедуры просто определяют координаты перемещения. По сути, в процедуре всего два запроса, но довольно сложных.
PHP код (3)
// Внутренняя процедура перемещения узла
function _move_unit ($data = array()) {
if ($data['near'] >= $this->unit['left'] && $data['near'] <= $this->unit['right']) {return 'ERR';}
$skew_tree = $this->unit['right'] - $this->unit['left'] + 1;
$skew_level = $data['level_new'] - $this->unit['level'];
// Перемещение вверх по дереву
if ($this->unit['right'] < $data['near']) {
$skew_edit = $data['near'] - $this->unit['left'] + 1 - $skew_tree;
$sql = 'UPDATE '.$this->table.'
SET '.
$this->left.' = CASE WHEN '.$this->right.'<='.$this->unit['right'].' THEN '.
$this->left.'+'.$skew_edit.' ELSE CASE WHEN '.$this->left.'>'.$this->unit['right'].' THEN '.
$this->left.'-'.$skew_tree.' ELSE '.$this->left.' END END, '.
$this->level.' = CASE WHEN '.$this->right.'<='.$this->unit['right'].' THEN '.
$this->level.'+'.$skew_level.' ELSE '.$this->level.' END, '.
$this->right.' = CASE WHEN '.$this->right.'<='.$this->unit['right'].' THEN '.
$this->right.'+'.$skew_edit.' ELSE CASE WHEN '.$this->right.'<='.$data['near'].' THEN '.
$this->right.'-'.$skew_tree.' ELSE '.$this->right.' END END
WHERE '.
$this->right.'>'.$this->unit['left'].' AND '.
$this->left.'<='.$data['near'].
($this->type == 'M' ? ' AND '.$this->multi.'='.$this->unit['multi'] : '');
$mysql_query = mysql_query($sql);
} else {
// Перемещение вниз по дереву
$skew_edit = $data['near'] - $this->unit['left'] + 1;
$sql = 'UPDATE '.$this->table.'
SET '.
$this->right.' = CASE WHEN '.$this->left.'>='.$this->unit['left'].' THEN '.
$this->right.'+'.$skew_edit.' ELSE CASE WHEN '.$this->right.'<'.$this->unit['left'].' THEN '.
$this->right.'+'.$skew_tree.' ELSE '.$this->right.' END END, '.
$this->level.' = CASE WHEN '.$this->left.'>='.$this->unit['left'].' THEN '.
$this->level.'+'.$skew_level.' ELSE '.$this->level.' END, '.
$this->left.' = CASE WHEN '.$this->left.'>='.$this->unit['left'].' THEN '.
$this->left.'+'.$skew_edit.' ELSE CASE WHEN '.$this->left.'>'.$data['near'].' THEN '.
$this->left.'+'.$skew_tree.' ELSE '.$this->left.' END END
WHERE '.
$this->right.'>'.$data['near'].' AND '.
$this->left.'<'.$this->unit['right'].
($this->type == 'M' ? ' AND '.$this->multi.'='.$this->unit['multi'] : '');
$mysql_query = mysql_query($sql);
}
return 'OK';
}
Продолжение следует...