/** * @param MPTT|int|array $target 实例或者主键ID * @param bool|int $leftColumn * @param bool|int $leftOffset * @param bool|int $levelOffset * @param bool|int $allowRootTarget * @return $this|bool * @throws \Doctrine\DBAL\DBALException */ protected function move($target, $leftColumn, $leftOffset, $levelOffset, $allowRootTarget) { if (!$this->loaded()) { return false; } // store the changed parent id before reload $parentID = $this->{$this->_parentColumn}; // 保证数据是最新的 $this->reload(); if (!$target instanceof $this) { $target = new self($target); if (!$target->loaded()) { return false; } } else { $target->reload(); } // Stop $this being moved into a descendant or itself or disallow if target is root if ($target->isDescendant($this) || $this->pk() === $target->pk() || $allowRootTarget === false && $target->isRoot()) { return false; } if ($levelOffset > 0) { // We're moving to a child node so add 1 to left offset. $leftOffset = $leftColumn === true ? $target->left() + 1 : $target->right() + $leftOffset; } else { $leftOffset = $leftColumn === true ? $target->left() : $target->right() + $leftOffset; } $levelOffset = $target->level() - $this->level() + $levelOffset; $size = $this->size(); $this->createSpace($leftOffset, $size); $this->reload(); $offset = $leftOffset - $this->left(); $this->db()->createQueryBuilder()->update($this->_tableName)->set($this->_leftColumn, $this->_leftColumn . '+' . $offset)->set($this->_rightColumn, $this->_rightColumn . '+' . $offset)->set($this->_levelColumn, $this->_levelColumn . '+' . $levelOffset)->set($this->_scopeColumn, $target->scope())->where($this->_leftColumn . '>=' . $this->left())->andWhere($this->_rightColumn . '<=' . $this->right())->andWhere($this->_scopeColumn . '=' . $this->scope())->execute(); $this->deleteSpace($this->left(), $size); // all went well so save the parent_id if changed if ($parentID != $this->{$this->_parentColumn}) { $this->{$this->_parentColumn} = $parentID; $this->save(); } $this->reload(); return $this; }
private function removeIn(RedBlackTree $t, $key) { if ($this->compare($key, $t->key()) < 0) { if (!$this->isRed($t->left()) && !$this->isRed($t->left()->left())) { $t = $this->moveRedLeft($t); } $t = new self($t->key(), $t->value(), $t->left()->remove($key), $t->right(), $t->color(), $t->isRoot()); } else { if ($this->isRed($t->left())) { $t = $this->rotateRight($t); } if ($this->compare($key, $t->key()) === 0 && $t->right()->isEmpty()) { return self::createEmpty(); } if (!$this->isRed($t->right()) && !$this->isRed($t->right()->left())) { $t = $this->moveRedRight($t); } if ($this->compare($key, $t->key()) === 0) { $min = $this->minIn($t->right()); $t = new self($min->key(), $min->value(), $t->left(), $this->removeMinIn($t->right()), $t->color(), $t->isRoot()); } else { $t = new self($t->key(), $t->value(), $t->left(), $t->right()->remove($key), $t->color(), $t->isRoot()); } } return $this->balance($t); }