/** * Move this item to the specified target. * * @chainable * @param Item_Model $target Target node * @return ORM_MTPP */ function move_to($target) { if ($this->left_ptr <= $target->left_ptr && $this->right_ptr >= $target->right_ptr) { throw new Exception("@todo INVALID_TARGET can't move item inside itself"); } $number_to_move = (int) (($this->right_ptr - $this->left_ptr) / 2 + 1); $size_of_hole = $number_to_move * 2; $original_left_ptr = $this->left_ptr; $original_right_ptr = $this->right_ptr; $target_right_ptr = $target->right_ptr; $level_delta = $target->level + 1 - $this->level; $this->lock(); try { if ($level_delta) { // Update the levels for the to-be-moved items $this->db->query("UPDATE {{$this->table_name}} SET `level` = `level` + {$level_delta}" . " WHERE `left_ptr` >= {$original_left_ptr} AND `right_ptr` <= {$original_right_ptr}"); } // Make a hole in the target for the move $target->db->query("UPDATE {{$this->table_name}} SET `left_ptr` = `left_ptr` + {$size_of_hole}" . " WHERE `left_ptr` >= {$target_right_ptr}"); $target->db->query("UPDATE {{$this->table_name}} SET `right_ptr` = `right_ptr` + {$size_of_hole}" . " WHERE `right_ptr` >= {$target_right_ptr}"); // Change the parent. $this->db->query("UPDATE {{$this->table_name}} SET `parent_id` = {$target->id}" . " WHERE `id` = {$this->id}"); // If the source is to the right of the target then we just adjusted its left_ptr and right_ptr above. $left_ptr = $original_left_ptr; $right_ptr = $original_right_ptr; if ($original_left_ptr > $target_right_ptr) { $left_ptr += $size_of_hole; $right_ptr += $size_of_hole; } $new_offset = $target->right_ptr - $left_ptr; $this->db->query("UPDATE {{$this->table_name}}" . " SET `left_ptr` = `left_ptr` + {$new_offset}," . " `right_ptr` = `right_ptr` + {$new_offset}" . " WHERE `left_ptr` >= {$left_ptr}" . " AND `right_ptr` <= {$right_ptr}"); // Close the hole in the source's parent after the move $this->db->query("UPDATE {{$this->table_name}} SET `left_ptr` = `left_ptr` - {$size_of_hole}" . " WHERE `left_ptr` > {$right_ptr}"); $this->db->query("UPDATE {{$this->table_name}} SET `right_ptr` = `right_ptr` - {$size_of_hole}" . " WHERE `right_ptr` > {$right_ptr}"); } catch (Exception $e) { $this->unlock(); throw $e; } $this->unlock(); // Lets reload to get the changes. $this->reload(); $target->reload(); return $this; }