public function move_term($term, $target_term = null, $before = false)
{
// We assume that the arguments passed are valid terms. Check them before calling this.
// If there are terms in the vocabulary, work out the reference point
if (!$this->is_empty()) {
$source_left = $term->mptt_left;
$source_right = $term->mptt_right;
$range = $source_right - $source_left + 1;
DB::begin_transaction();
// Determine the insertion point mptt_target
if ($target_term == null) {
// if no target is specified, put the new term after the last term
$mptt_target = DB::get_value('SELECT MAX(mptt_right) FROM {terms} WHERE vocabulary_id = :id', array(':id' => $this->id));
$mptt_target = $mptt_target + 1;
// the left is one greater than the highest right
} else {
// if we're putting it before
if ($before) {
$mptt_target = $target_term->mptt_left;
// we're actually taking the place of the target term's left
} else {
$mptt_target = $target_term->mptt_right + 1;
// we just need to start at the next number
}
}
// Create space in the tree for the insertion
$params = array('vocab_id' => $this->id, 'range' => $range, 'mptt_target' => $mptt_target);
$res = DB::query('UPDATE {terms} SET mptt_left = mptt_left + :range WHERE vocabulary_id = :vocab_id AND mptt_left >= :mptt_target', $params);
if (!$res) {
DB::rollback();
return false;
}
$res = DB::query('UPDATE {terms} SET mptt_right = mptt_right + :range WHERE vocabulary_id = :vocab_id AND mptt_right >= :mptt_target', $params);
if (!$res) {
DB::rollback();
return false;
}
// if we're moving it "down" ("forward"?) in the vocabulary, we just created a gap that changed our term's left and right values
if ($mptt_target < $source_left) {
$source_left = $source_left + $range;
$source_right = $source_right + $range;
}
// figure out how far our nodes are moving
$offset = $mptt_target - $source_left;
// move our lucky nodes into the space we just created
$params = array(':offset' => $offset, ':vocab_id' => $this->id, ':source_left' => $source_left, ':source_right' => $source_right);
$res = DB::query('
UPDATE {terms}
SET
mptt_left = mptt_left + :offset,
mptt_right = mptt_right + :offset
WHERE
vocabulary_id = :vocab_id AND
mptt_left >= :source_left AND
mptt_right <= :source_right
', $params);
// Close the gap in the tree created by moving those nodes out
$params = array('range' => $range, 'vocab_id' => $this->id, 'source_left' => $source_left);
$res = DB::query('UPDATE {terms} SET mptt_left = mptt_left - :range WHERE vocabulary_id = :vocab_id AND mptt_left > :source_left', $params);
if (!$res) {
DB::rollback();
return false;
}
$params = array('range' => $range, 'vocab_id' => $this->id, 'source_right' => $source_right);
$res = DB::query('UPDATE {terms} SET mptt_right = mptt_right - :range WHERE vocabulary_id = :vocab_id AND mptt_right > :source_right', $params);
if (!$res) {
DB::rollback();
return false;
}
// Success!
DB::commit();
return $this->get_term($term->id);
}
return false;
}