/** * @param \Phalcon\Mvc\ModelInterface $target * @param int $key * @param int $levelUp * * @return boolean * @throws PMMException */ private function moveNode($target, $key, $levelUp) { $owner = $this->getOwner(); if (!$target) { throw new PMMException('Target node is not defined.'); } if ($this->getIsNewRecord()) { throw new PMMException('The node should not be new record.'); } if ($this->getIsDeletedRecord()) { throw new PMMException('The node should not be deleted.'); } if ($target->getIsDeletedRecord()) { throw new PMMException('The target node should not be deleted.'); } if ($owner == $target) { throw new PMMException('The target node should not be self.'); } if ($target->isDescendantOf($owner)) { throw new PMMException('The target node should not be descendant.'); } if (!$levelUp && $target->isRoot()) { throw new PMMException('The target node should not be root.'); } $owner->getDI()->getDb()->begin(); $left = $owner->{$this->leftAttribute}; $right = $owner->{$this->rightAttribute}; $levelDelta = $target->{$this->levelAttribute} - $owner->{$this->levelAttribute} + $levelUp; if ($this->hasManyRoots && $owner->{$this->rootAttribute} !== $target->{$this->rootAttribute}) { $this->ignoreEvent = true; foreach (array($this->leftAttribute, $this->rightAttribute) as $attribute) { $condition = $attribute . '>=' . $key . ' AND ' . $this->rootAttribute . '=' . $target->{$this->rootAttribute}; foreach ($owner::find($condition) as $i) { if ($i->update(array($attribute => $i->{$attribute} + $right - $left + 1)) == false) { $owner->getDI()->getDb()->rollback(); $this->ignoreEvent = false; return false; } } } $delta = $key - $left; $condition = $this->leftAttribute . '>=' . $left . ' AND '; $condition .= $this->rightAttribute . '<=' . $right . ' AND '; $condition .= $this->rootAttribute . '=' . $target->{$this->rootAttribute}; foreach ($owner::find($condition) as $i) { $arr = array($this->leftAttribute => $i->{$this->leftAttribute} + $delta, $this->rightAttribute => $i->{$this->rightAttribute} + $delta, $this->levelAttribute => $i->{$this->levelAttribute} + $levelDelta, $this->rootAttribute => $target->{$this->rootAttribute}); if ($i->update($arr) == false) { $owner->getDI()->getDb()->rollback(); $this->ignoreEvent = false; return false; } } $this->ignoreEvent = false; $this->shiftLeftRight($right + 1, $left - $right - 1); $owner->getDI()->getDb()->commit(); } else { $delta = $right - $left + 1; $this->shiftLeftRight($key, $delta); if ($left >= $key) { $left += $delta; $right += $delta; } $condition = $this->leftAttribute . '>=' . $left . ' AND ' . $this->rightAttribute . '<=' . $right; if ($this->hasManyRoots) { $condition .= ' AND ' . $this->rootAttribute . '=' . $owner->{$this->rootAttribute}; } $this->ignoreEvent = true; foreach ($owner::find($condition) as $i) { if ($i->update(array($this->levelAttribute => $i->{$this->levelAttribute} + $levelDelta)) == false) { $owner->getDI()->getDb()->rollback(); $this->ignoreEvent = false; return false; } } foreach (array($this->leftAttribute, $this->rightAttribute) as $attribute) { $condition = $attribute . '>=' . $left . ' AND ' . $attribute . '<=' . $right; if ($this->hasManyRoots) { $condition .= ' AND ' . $this->rootAttribute . '=' . $owner->{$this->rootAttribute}; } foreach ($owner::find($condition) as $i) { if ($i->update(array($attribute => $i->{$attribute} + $key - $left)) == false) { $owner->getDI()->getDb()->rollback(); $this->ignoreEvent = false; return false; } } } $this->ignoreEvent = false; $this->shiftLeftRight($right + 1, -$delta); $owner->getDI()->getDb()->commit(); } return true; }
/** * @param ModelInterface $target * @param int $key * @param int $levelUp * * @return boolean * @throws Exception */ private function moveNode(ModelInterface $target, $key, $levelUp) { $owner = $this->getOwner(); if ($this->getIsNewRecord()) { throw new Exception('The node should not be new record.'); } if ($this->getIsDeletedRecord()) { throw new Exception('The node should not be deleted.'); } if ($target->getIsDeletedRecord()) { throw new Exception('The target node should not be deleted.'); } if ($owner == $target) { throw new Exception('The target node should not be self.'); } if ($target->isDescendantOf($owner)) { throw new Exception('The target node should not be descendant.'); } if (!$levelUp && $target->isRoot()) { throw new Exception('The target node should not be root.'); } $this->db->begin(); $left = $owner->{$this->leftAttribute}; $right = $owner->{$this->rightAttribute}; $levelDelta = $target->{$this->levelAttribute} - $owner->{$this->levelAttribute} + $levelUp; if ($this->hasManyRoots && $owner->{$this->rootAttribute} !== $target->{$this->rootAttribute}) { $this->ignoreEvent = true; // 1. Rebuild the target tree foreach ([$this->leftAttribute, $this->rightAttribute] as $attribute) { $condition = join(' AND ', [$attribute . '>=' . $key, $this->rootAttribute . '=' . $target->{$this->rootAttribute}]); foreach ($target::find($condition) as $i) { $delta = $right - $left + 1; /** @var ModelInterface $i */ if (!$i->update([$attribute => $i->{$attribute} + $delta])) { $this->db->rollback(); $this->ignoreEvent = false; return false; } } } $delta = $key - $left; // 2. Rebuild the owner's tree of children (owner sub-tree) $condition = $this->leftAttribute . '>=' . $left . ' AND '; $condition .= $this->rightAttribute . '<=' . $right . ' AND '; $condition .= $this->rootAttribute . '=' . $owner->{$this->rootAttribute}; foreach ($owner::find($condition) as $i) { $arr = [$this->leftAttribute => $i->{$this->leftAttribute} + $delta, $this->rightAttribute => $i->{$this->rightAttribute} + $delta, $this->levelAttribute => $i->{$this->levelAttribute} + $levelDelta, $this->rootAttribute => $target->{$this->rootAttribute}]; if ($i->update($arr) == false) { $this->db->rollback(); $this->ignoreEvent = false; return false; } } // 3. Rebuild the owner tree $this->shiftLeftRight($right + 1, $left - $right - 1, $owner); $this->ignoreEvent = false; $this->db->commit(); } else { $delta = $right - $left + 1; $this->ignoreEvent = true; $this->shiftLeftRight($key, $delta); if ($left >= $key) { $left += $delta; $right += $delta; } $condition = $this->leftAttribute . '>=' . $left . ' AND ' . $this->rightAttribute . '<=' . $right; if ($this->hasManyRoots) { $condition .= ' AND ' . $this->rootAttribute . '=' . $owner->{$this->rootAttribute}; } foreach ($owner::find($condition) as $i) { if ($i->update([$this->levelAttribute => $i->{$this->levelAttribute} + $levelDelta]) == false) { $this->db->rollback(); $this->ignoreEvent = false; return false; } } foreach ([$this->leftAttribute, $this->rightAttribute] as $attribute) { $condition = $attribute . '>=' . $left . ' AND ' . $attribute . '<=' . $right; if ($this->hasManyRoots) { $condition .= ' AND ' . $this->rootAttribute . '=' . $owner->{$this->rootAttribute}; } foreach ($owner::find($condition) as $i) { if ($i->update([$attribute => $i->{$attribute} + $key - $left]) == false) { $this->db->rollback(); $this->ignoreEvent = false; return false; } } } $this->shiftLeftRight($right + 1, -$delta); $this->ignoreEvent = false; $this->ignoreEvent = false; $this->db->commit(); } return true; }