API16

JTableNested/move

From Joomla! Documentation

< API16:JTableNested

The "API16" namespace is an archived namespace. This page contains information for a Joomla! version which is no longer supported. It exists only as a historical reference, it will not be improved and its content may be incomplete and/or contain broken links.

Description[edit]

Method to move a node and its children to a new location in the tree.



Syntax[edit]

move($referenceId, $position= 'after', $pk=null)
Parameter Name Default Value Description
$referenceId The primary key of the node to reference new location by.
$position 'after' Location type string. ['before', 'after', 'first-child', 'last-child']
$pk null The primary key of the node to move.

Returns[edit]

boolean True on success.

Defined in[edit]

libraries/joomla/database/tablenested.php

Importing[edit]

jimport( 'joomla.database.tablenested' );

Source Body[edit]

public function move($referenceId, $position = 'after', $pk = null)
{
        if ($this->_debug) {
                echo "\nMoving ReferenceId:$referenceId, Position:$position, PK:$pk";
        }

        // Initialise variables.
        $k = $this->_tbl_key;
        $pk = (is_null($pk)) ? $this->$k : $pk;

        // Get the node by id.
        if (!$node = $this->_getNode($pk)) {
                // Error message set in getNode method.
                return false;
        }

        // Get the ids of child nodes.
        $this->_db->setQuery(
                'SELECT `'.$k.'`' .
                ' FROM `'.$this->_tbl.'`' .
                ' WHERE `lft` BETWEEN '.(int) $node->lft.' AND '.(int) $node->rgt
        );
        $children = $this->_db->loadResultArray();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                return false;
        }
        if ($this->_debug) {
                $this->_logtable(false);
        }

        // Cannot move the node to be a child of itself.
        if (in_array($referenceId, $children)) {
                $this->setError(JText::_('Invalid_Node_Recursion'));
                return false;
        }

        // Lock the table for writing.
        if (!$this->_lock()) {
                // Error message set in lock method.
                return false;
        }

        // We are moving the tree relative to a reference node.
        if ($referenceId) {
                // Get the reference node by primary key.
                if (!$reference = $this->_getNode($referenceId)) {
                        // Error message set in getNode method.
                        $this->_unlock();
                        return false;
                }

                // If moving "down" the tree, adjust $reference lft, rgt for $node width
                if ($node->rgt < $reference->rgt) {
                        $reference->lft -= $node->width;
                        $reference->rgt -= $node->width;
                }

                // Get the reposition data for shifting the tree and re-inserting the node.
                if (!$repositionData = $this->_getTreeRepositionData($reference, $node->width, $position)) {
                        // Error message set in getNode method.
                        $this->_unlock();
                        return false;
                }
        }

        // We are moving the tree to be a new root node.
        else {
                // Get the last root node as the reference node.
                $this->_db->setQuery(
                        'SELECT `'.$this->_tbl_key.'`, `parent_id`, `level`, `lft`, `rgt`' .
                        ' FROM `'.$this->_tbl.'`' .
                        ' WHERE `parent_id` = 0' .
                        ' ORDER BY `lft` DESC',
                        0, 1
                );
                $reference = $this->_db->loadObject();

                // Check for a database error.
                if ($this->_db->getErrorNum()) {
                        $this->setError($this->_db->getErrorMsg());
                        $this->_unlock();
                        return false;
                }
                if ($this->_debug) {
                        $this->_logtable(false);
                }

                // Get the reposition data for re-inserting the node after the found root.
                if (!$repositionData = $this->_getTreeRepositionData($reference, $node->width, 'after')) {
                        // Error message set in getNode method.
                        $this->_unlock();
                        return false;
                }
        }

        /*
         * Move the sub-tree out of the nested sets by negating its left and right values.
         */
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `lft` = `lft` * (-1), `rgt` = `rgt` * (-1)' .
                ' WHERE `lft` BETWEEN '.(int) $node->lft.' AND '.(int) $node->rgt
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        /*
         * Close the hole in the tree that was opened by removing the sub-tree from the nested sets.
         */
        // Compress the left values.
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `lft` = `lft` - '.(int) $node->width .
                ' WHERE `lft` > '.(int) $node->rgt
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        // Compress the right values.
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `rgt` = `rgt` - '.(int) $node->width .
                ' WHERE `rgt` > '.(int) $node->rgt
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        /*
         * Create space in the nested sets at the new location for the moved sub-tree.
         */
        // Shift left values.
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `lft` = `lft` + '.(int) $node->width .
                ' WHERE '.$repositionData->left_where
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        // Shift right values.
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `rgt` = `rgt` + '.(int) $node->width .
                ' WHERE '.$repositionData->right_where
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        /*
         * Calculate the offset between where the node used to be in the tree and
         * where it needs to be in the tree for left ids (also works for right ids).
         */
        $offset = $repositionData->new_lft - $node->lft;
        $levelOffset = $repositionData->new_level - $node->level;

        // Move the nodes back into position in the tree using the calculated offsets.
        $this->_db->setQuery(
                'UPDATE `'.$this->_tbl.'`' .
                ' SET `rgt` = '.(int) $offset.' - `rgt`,' .
                '       `lft` = '.(int) $offset.' - `lft`,' .
                '       `level` = `level` + '.(int) $levelOffset .
                ' WHERE `lft` < 0'
        );
        $this->_db->query();

        // Check for a database error.
        if ($this->_db->getErrorNum()) {
                $this->setError($this->_db->getErrorMsg());
                $this->_unlock();
                return false;
        }
        if ($this->_debug) {
                $this->_logtable();
        }

        // Set the correct parent id for the moved node if required.
        if ($node->parent_id != $repositionData->new_parent_id) {
                $this->_db->setQuery(
                        'UPDATE `'.$this->_tbl.'`' .
                        ' SET `parent_id` = '.(int) $repositionData->new_parent_id .
                        ' WHERE `'.$this->_tbl_key.'` = '.(int) $node->$k
                );
                $this->_db->query();

                // Check for a database error.
                if ($this->_db->getErrorNum()) {
                        $this->setError($this->_db->getErrorMsg());
                        $this->_unlock();
                        return false;
                }
                if ($this->_debug) {
                        $this->_logtable();
                }
        }

        // Unlock the table for writing.
        $this->_unlock();

        // Set the object values.
        $this->parent_id = $repositionData->new_parent_id;
        $this->level = $repositionData->new_level;
        $this->lft = $repositionData->new_lft;
        $this->rgt = $repositionData->new_rgt;

        return true;
}



Examples[edit]

Code Examples[edit]