Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
9df0b72c
Commit
9df0b72c
authored
Jan 12, 2007
by
zYne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
--no commit message
--no commit message
parent
1f54f672
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
690 additions
and
690 deletions
+690
-690
NestedSet.php
draft/Node/NestedSet.php
+690
-690
No files found.
draft/Node/NestedSet.php
View file @
9df0b72c
<?php
/*
* $Id$
*
$Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
...
...
@@ -21,703 +21,703 @@
/**
* Doctrine_Node_NestedSet
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
* @package
Doctrine
* @license
http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category
Object Relational Mapping
* @link
www.phpdoctrine.com
* @since
1.0
* @version
$Revision$
* @author
Joe Simms <joe.simms@websites4.com>
*/
class
Doctrine_Node_NestedSet
extends
Doctrine_Node
implements
Doctrine_Node_Interface
{
/**
* test if node has previous sibling
*
* @return bool
*/
public
function
hasPrevSibling
()
{
return
$this
->
isValidNode
(
$this
->
getPrevSibling
());
}
/**
* test if node has next sibling
*
* @return bool
*/
public
function
hasNextSibling
()
{
return
$this
->
isValidNode
(
$this
->
getNextSibling
());
}
/**
* test if node has children
*
* @return bool
*/
public
function
hasChildren
()
{
return
((
$this
->
getRightValue
()
-
$this
->
getLeftValue
()
)
>
1
);
}
/**
* test if node has parent
*
* @return bool
*/
public
function
hasParent
()
{
return
!
$this
->
isRoot
();
}
/**
* gets record of prev sibling or empty record
*
* @return object Doctrine_Record
*/
public
function
getPrevSibling
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'rgt = ?'
,
$this
->
getLeftValue
()
-
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets record of next sibling or empty record
*
* @return object Doctrine_Record
*/
public
function
getNextSibling
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'lft = ?'
,
$this
->
getRightValue
()
+
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets siblings for node
*
* @return array array of sibling Doctrine_Record objects
*/
public
function
getSiblings
(
$includeNode
=
false
)
{
$parent
=
$this
->
getParent
();
$siblings
=
array
();
if
(
$parent
->
exists
())
{
foreach
(
$parent
->
getNode
()
->
getChildren
()
as
$child
)
{
if
(
$this
->
isEqualTo
(
$child
)
&&
!
$includeNode
)
continue
;
$siblings
[]
=
$child
;
}
}
return
$siblings
;
}
/**
* gets record of first child or empty record
*
* @return object Doctrine_Record
*/
public
function
getFirstChild
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'lft = ?'
,
$this
->
getLeftValue
()
+
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets record of last child or empty record
*
* @return object Doctrine_Record
*/
public
function
getLastChild
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'rgt = ?'
,
$this
->
getRightValue
()
-
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets children for node (direct descendants only)
*
* @return array array of sibling Doctrine_Record objects
*/
public
function
getChildren
()
{
return
$this
->
getIterator
(
'Pre'
,
array
(
'depth'
=>
1
));
}
/**
* gets descendants for node (direct descendants only)
*
* @return iterator iterator to traverse descendants from node
*/
public
function
getDescendants
()
{
return
$this
->
getIterator
();
}
/**
* gets record of parent or empty record
*
* @return object Doctrine_Record
*/
public
function
getParent
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$parent
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()))
->
orderBy
(
'rgt asc'
)
->
execute
()
->
getFirst
();
if
(
!
$parent
)
$parent
=
$this
->
record
->
getTable
()
->
create
();
return
$parent
;
}
/**
* gets ancestors for node
*
* @return object Doctrine_Collection
*/
public
function
getAncestors
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$ancestors
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()))
->
orderBy
(
'lft asc'
)
->
execute
();
return
$ancestors
;
}
/**
* gets path to node from root, uses record::toString() method to get node names
*
* @param string $seperator path seperator
* @param bool $includeNode whether or not to include node at end of path
* @return string string representation of path
*/
public
function
getPath
(
$seperator
=
' > '
,
$includeRecord
=
false
)
{
$path
=
array
();
$ancestors
=
$this
->
getAncestors
();
foreach
(
$ancestors
as
$ancestor
)
{
$path
[]
=
$ancestor
->
__toString
();
}
if
(
$includeRecord
)
$path
[]
=
$this
->
getRecord
()
->
__toString
();
/**
* test if node has previous sibling
*
* @return bool
*/
public
function
hasPrevSibling
()
{
return
$this
->
isValidNode
(
$this
->
getPrevSibling
());
}
/**
* test if node has next sibling
*
* @return bool
*/
public
function
hasNextSibling
()
{
return
$this
->
isValidNode
(
$this
->
getNextSibling
());
}
/**
* test if node has children
*
* @return bool
*/
public
function
hasChildren
()
{
return
((
$this
->
getRightValue
()
-
$this
->
getLeftValue
()
)
>
1
);
}
/**
* test if node has parent
*
* @return bool
*/
public
function
hasParent
()
{
return
!
$this
->
isRoot
();
}
/**
* gets record of prev sibling or empty record
*
* @return object Doctrine_Record
*/
public
function
getPrevSibling
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'rgt = ?'
,
$this
->
getLeftValue
()
-
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets record of next sibling or empty record
*
* @return object Doctrine_Record
*/
public
function
getNextSibling
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'lft = ?'
,
$this
->
getRightValue
()
+
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets siblings for node
*
* @return array array of sibling Doctrine_Record objects
*/
public
function
getSiblings
(
$includeNode
=
false
)
{
$parent
=
$this
->
getParent
();
$siblings
=
array
();
if
(
$parent
->
exists
())
{
foreach
(
$parent
->
getNode
()
->
getChildren
()
as
$child
)
{
if
(
$this
->
isEqualTo
(
$child
)
&&
!
$includeNode
)
continue
;
$siblings
[]
=
$child
;
}
}
return
implode
(
$seperator
,
$path
);
}
/**
* gets number of children (direct descendants)
*
* @return int
*/
public
function
getNumberChildren
()
{
$count
=
0
;
$children
=
$this
->
getChildren
();
while
(
$children
->
next
())
{
$count
++
;
}
return
$count
;
}
/**
* gets number of descendants (children and their children)
*
* @return int
*/
public
function
getNumberDescendants
()
{
return
(
$this
->
getRightValue
()
-
$this
->
getLeftValue
()
-
1
)
/
2
;
}
/**
* inserts node as parent of dest record
*
* @return bool
*/
public
function
insertAsParentOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
return
$siblings
;
}
/**
* gets record of first child or empty record
*
* @return object Doctrine_Record
*/
public
function
getFirstChild
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'lft = ?'
,
$this
->
getLeftValue
()
+
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets record of last child or empty record
*
* @return object Doctrine_Record
*/
public
function
getLastChild
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$result
=
$q
->
where
(
'rgt = ?'
,
$this
->
getRightValue
()
-
1
)
->
execute
()
->
getFirst
();
if
(
!
$result
)
$result
=
$this
->
record
->
getTable
()
->
create
();
return
$result
;
}
/**
* gets children for node (direct descendants only)
*
* @return array array of sibling Doctrine_Record objects
*/
public
function
getChildren
()
{
return
$this
->
getIterator
(
'Pre'
,
array
(
'depth'
=>
1
));
}
/**
* gets descendants for node (direct descendants only)
*
* @return iterator iterator to traverse descendants from node
*/
public
function
getDescendants
()
{
return
$this
->
getIterator
();
}
/**
* gets record of parent or empty record
*
* @return object Doctrine_Record
*/
public
function
getParent
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$parent
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()))
->
orderBy
(
'rgt asc'
)
->
execute
()
->
getFirst
();
if
(
!
$parent
)
$parent
=
$this
->
record
->
getTable
()
->
create
();
return
$parent
;
}
/**
* gets ancestors for node
*
* @return object Doctrine_Collection
*/
public
function
getAncestors
()
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$ancestors
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()))
->
orderBy
(
'lft asc'
)
->
execute
();
return
$ancestors
;
}
/**
* gets path to node from root, uses record::toString() method to get node names
*
* @param string $seperator path seperator
* @param bool $includeNode whether or not to include node at end of path
* @return string string representation of path
*/
public
function
getPath
(
$seperator
=
' > '
,
$includeRecord
=
false
)
{
$path
=
array
();
$ancestors
=
$this
->
getAncestors
();
foreach
(
$ancestors
as
$ancestor
)
{
$path
[]
=
$ancestor
->
__toString
();
}
if
(
$includeRecord
)
$path
[]
=
$this
->
getRecord
()
->
__toString
();
return
implode
(
$seperator
,
$path
);
}
/**
* gets number of children (direct descendants)
*
* @return int
*/
public
function
getNumberChildren
()
{
$count
=
0
;
$children
=
$this
->
getChildren
();
// cannot insert as parent of root
if
(
$dest
->
getNode
()
->
isRoot
())
return
false
;
$this
->
shiftRLValues
(
$dest
->
getNode
()
->
getLeftValue
(),
1
);
$this
->
shiftRLValues
(
$dest
->
getNode
()
->
getRightValue
()
+
2
,
1
);
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
();
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
while
(
$children
->
next
())
{
$count
++
;
}
return
$count
;
}
/**
* gets number of descendants (children and their children)
*
* @return int
*/
public
function
getNumberDescendants
()
{
return
(
$this
->
getRightValue
()
-
$this
->
getLeftValue
()
-
1
)
/
2
;
}
/**
* inserts node as parent of dest record
*
* @return bool
*/
public
function
insertAsParentOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
// cannot insert as parent of root
if
(
$dest
->
getNode
()
->
isRoot
())
return
false
;
$this
->
shiftRLValues
(
$dest
->
getNode
()
->
getLeftValue
(),
1
);
$this
->
shiftRLValues
(
$dest
->
getNode
()
->
getRightValue
()
+
2
,
1
);
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
();
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
return
true
;
}
/**
* inserts node as previous sibling of dest record
*
* @return bool
*/
public
function
insertAsPrevSiblingOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
();
$newRight
=
$dest
->
getNode
()
->
getLeftValue
()
+
1
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setLeftValue($dest->getNode()->getLeftValue() + 2);
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
return
true
;
}
/**
* inserts node as next sibling of dest record
*
* @return bool
*/
public
function
insertAsNextSiblingOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getRightValue
()
+
1
;
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// no need, node not affected
return
true
;
}
/**
* inserts node as first child of dest record
*
* @return bool
*/
public
function
insertAsFirstChildOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
()
+
1
;
$newRight
=
$dest
->
getNode
()
->
getLeftValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
return
true
;
}
/**
* inserts node as last child of dest record
*
* @return bool
*/
public
function
insertAsLastChildOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getRightValue
();
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
1
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
return
true
;
}
/**
* moves node as prev sibling of dest record
*
*/
public
function
moveAsPrevSiblingOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getLeftValue
());
}
/**
* moves node as next sibling of dest record
*
*/
public
function
moveAsNextSiblingOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getRightValue
()
+
1
);
}
/**
* moves node as first child of dest record
*
*/
public
function
moveAsFirstChildOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getLeftValue
()
+
1
);
}
/**
* moves node as last child of dest record
*
*/
public
function
moveAsLastChildOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getRightValue
());
}
/**
* adds node as last child of record
*
*/
public
function
addChild
(
Doctrine_Record
$record
)
{
$record
->
getNode
()
->
insertAsLastChildOf
(
$this
->
getRecord
());
}
/**
* determines if node is leaf
*
* @return bool
*/
public
function
isLeaf
()
{
return
((
$this
->
getRightValue
()
-
$this
->
getLeftValue
())
==
1
);
}
/**
* determines if node is root
*
* @return bool
*/
public
function
isRoot
()
{
return
(
$this
->
getLeftValue
()
==
1
);
}
/**
* determines if node is equal to subject node
*
* @return bool
*/
public
function
isEqualTo
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
==
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
==
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is child of subject node
*
* @return bool
*/
public
function
isDescendantOf
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
>
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
<
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is child of or sibling to subject node
*
* @return bool
*/
public
function
isDescendantOfOrEqualTo
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
>=
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
<=
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is valid
*
* @return bool
*/
public
function
isValidNode
()
{
return
(
$this
->
getRightValue
()
>
$this
->
getLeftValue
());
}
/**
* deletes node and it's descendants
*
*/
public
function
delete
()
{
// TODO: add the setting whether or not to delete descendants or relocate children
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$componentName
=
$this
->
record
->
getTable
()
->
getComponentName
();
$q
=
$q
->
where
(
"
$componentName
.lft >= ? AND
$componentName
.rgt <= ?"
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()));
$q
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$q
,
$this
->
getRootValue
());
$coll
=
$q
->
execute
();
$coll
->
delete
();
$first
=
$this
->
getRightValue
()
+
1
;
$delta
=
$this
->
getLeftValue
()
-
$this
->
getRightValue
()
-
1
;
$this
->
shiftRLValues
(
$first
,
$delta
);
return
true
;
}
/**
* sets node's left and right values and save's it
*
* @param int $destLeft node left value
* @param int $destRight node right value
*/
private
function
insertNode
(
$destLeft
=
0
,
$destRight
=
0
,
$destRoot
=
1
)
{
$this
->
setLeftValue
(
$destLeft
);
$this
->
setRightValue
(
$destRight
);
$this
->
setRootValue
(
$destRoot
);
$this
->
record
->
save
();
}
/**
* move node's and its children to location $destLeft and updates rest of tree
*
* @param int $destLeft destination left value
*/
private
function
updateNode
(
$destLeft
)
{
$left
=
$this
->
getLeftValue
();
$right
=
$this
->
getRightValue
();
$treeSize
=
$right
-
$left
+
1
;
$this
->
shiftRLValues
(
$destLeft
,
$treeSize
);
if
(
$left
>=
$destLeft
){
// src was shifted too?
$left
+=
$treeSize
;
$right
+=
$treeSize
;
}
// now there's enough room next to target to move the subtree
$this
->
shiftRLRange
(
$left
,
$right
,
$destLeft
-
$left
);
// correct values after source
$this
->
shiftRLValues
(
$right
+
1
,
-
$treeSize
);
$this
->
record
->
save
();
$this
->
record
->
refresh
();
}
/**
* adds '$delta' to all Left and Right values that are >= '$first'. '$delta' can also be negative.
*
* @param int $first First node to be shifted
* @param int $delta Value to be shifted by, can be negative
*/
private
function
shiftRLValues
(
$first
,
$delta
,
$root_id
=
1
)
{
$qLeft
=
$this
->
record
->
getTable
()
->
createQuery
();
$qRight
=
$this
->
record
->
getTable
()
->
createQuery
();
// TODO: Wrap in transaction
// shift left columns
$qLeft
=
$qLeft
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'lft'
,
"lft +
$delta
"
)
->
where
(
'lft >= ?'
,
$first
);
$qLeft
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qLeft
,
$root_id
);
$resultLeft
=
$qLeft
->
execute
();
// shift right columns
$resultRight
=
$qRight
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'rgt'
,
"rgt +
$delta
"
)
->
where
(
'rgt >= ?'
,
$first
);
$qRight
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qRight
,
$root_id
);
$resultRight
=
$qRight
->
execute
();
}
/**
* adds '$delta' to all Left and Right values that are >= '$first' and <= '$last'.
* '$delta' can also be negative.
*
* @param int $first First node to be shifted (L value)
* @param int $last Last node to be shifted (L value)
* @param int $delta Value to be shifted by, can be negative
*/
private
function
shiftRLRange
(
$first
,
$last
,
$delta
,
$root_id
=
1
)
{
$qLeft
=
$this
->
record
->
getTable
()
->
createQuery
();
$qRight
=
$this
->
record
->
getTable
()
->
createQuery
();
// TODO : Wrap in transaction
// shift left column values
$qLeft
=
$qLeft
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'lft'
,
"lft +
$delta
"
)
->
where
(
'lft >= ? AND lft <= ?'
,
array
(
$first
,
$last
));
$qLeft
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qLeft
,
$root_id
);
$resultLeft
=
$qLeft
->
execute
();
// shift right column values
$qRight
=
$qRight
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'rgt'
,
"rgt +
$delta
"
)
->
where
(
'rgt >= ? AND rgt <= ?'
,
array
(
$first
,
$last
));
$qRight
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qRight
,
$root_id
);
$resultRight
=
$qRight
->
execute
();
}
return
true
;
}
/**
* inserts node as previous sibling of dest record
*
* @return bool
*/
public
function
insertAsPrevSiblingOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
();
$newRight
=
$dest
->
getNode
()
->
getLeftValue
()
+
1
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setLeftValue($dest->getNode()->getLeftValue() + 2);
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
/**
* gets record's left value
*
* @return int
*/
public
function
getLeftValue
()
{
return
$this
->
record
->
get
(
'lft'
);
}
/**
* sets record's left value
*
* @param int
*/
public
function
setLeftValue
(
$lft
)
{
$this
->
record
->
set
(
'lft'
,
$lft
);
}
/**
* gets record's right value
*
* @return int
*/
public
function
getRightValue
()
{
return
$this
->
record
->
get
(
'rgt'
);
}
/**
* sets record's right value
*
* @param int
*/
public
function
setRightValue
(
$rgt
)
{
$this
->
record
->
set
(
'rgt'
,
$rgt
);
}
/**
* gets level (depth) of node in the tree
*
* @return int
*/
public
function
getLevel
()
{
if
(
!
isset
(
$this
->
level
))
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$q
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()));
$q
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$q
,
$this
->
getRootValue
());
return
true
;
}
/**
* inserts node as next sibling of dest record
*
* @return bool
*/
public
function
insertAsNextSiblingOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getRightValue
()
+
1
;
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// no need, node not affected
return
true
;
}
/**
* inserts node as first child of dest record
*
* @return bool
*/
public
function
insertAsFirstChildOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getLeftValue
()
+
1
;
$newRight
=
$dest
->
getNode
()
->
getLeftValue
()
+
2
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
return
true
;
}
/**
* inserts node as last child of dest record
*
* @return bool
*/
public
function
insertAsLastChildOf
(
Doctrine_Record
$dest
)
{
// cannot insert a node that has already has a place within the tree
if
(
$this
->
isValidNode
())
return
false
;
$newLeft
=
$dest
->
getNode
()
->
getRightValue
();
$newRight
=
$dest
->
getNode
()
->
getRightValue
()
+
1
;
$newRoot
=
$dest
->
getNode
()
->
getRootValue
();
$this
->
shiftRLValues
(
$newLeft
,
2
,
$newRoot
);
$this
->
insertNode
(
$newLeft
,
$newRight
,
$newRoot
);
// update destination left/right values to prevent a refresh
// $dest->getNode()->setRightValue($dest->getNode()->getRightValue() + 2);
return
true
;
}
/**
* moves node as prev sibling of dest record
*
*/
public
function
moveAsPrevSiblingOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getLeftValue
());
}
/**
* moves node as next sibling of dest record
*
*/
public
function
moveAsNextSiblingOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getRightValue
()
+
1
);
}
/**
* moves node as first child of dest record
*
*/
public
function
moveAsFirstChildOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getLeftValue
()
+
1
);
}
/**
* moves node as last child of dest record
*
*/
public
function
moveAsLastChildOf
(
Doctrine_Record
$dest
)
{
$this
->
updateNode
(
$dest
->
getNode
()
->
getRightValue
());
}
/**
* adds node as last child of record
*
*/
public
function
addChild
(
Doctrine_Record
$record
)
{
$record
->
getNode
()
->
insertAsLastChildOf
(
$this
->
getRecord
());
}
/**
* determines if node is leaf
*
* @return bool
*/
public
function
isLeaf
()
{
return
((
$this
->
getRightValue
()
-
$this
->
getLeftValue
())
==
1
);
}
/**
* determines if node is root
*
* @return bool
*/
public
function
isRoot
()
{
return
(
$this
->
getLeftValue
()
==
1
);
}
/**
* determines if node is equal to subject node
*
* @return bool
*/
public
function
isEqualTo
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
==
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
==
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is child of subject node
*
* @return bool
*/
public
function
isDescendantOf
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
>
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
<
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is child of or sibling to subject node
*
* @return bool
*/
public
function
isDescendantOfOrEqualTo
(
Doctrine_Record
$subj
)
{
return
((
$this
->
getLeftValue
()
>=
$subj
->
getNode
()
->
getLeftValue
())
and
(
$this
->
getRightValue
()
<=
$subj
->
getNode
()
->
getRightValue
())
and
(
$this
->
getRootValue
()
==
$subj
->
getNode
()
->
getRootValue
()));
}
/**
* determines if node is valid
*
* @return bool
*/
public
function
isValidNode
()
{
return
(
$this
->
getRightValue
()
>
$this
->
getLeftValue
());
}
/**
* deletes node and it's descendants
*
*/
public
function
delete
()
{
// TODO: add the setting whether or not to delete descendants or relocate children
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$componentName
=
$this
->
record
->
getTable
()
->
getComponentName
();
$coll
=
$q
->
execute
();
$q
=
$q
->
where
(
"
$componentName
.lft >= ? AND
$componentName
.rgt <= ?"
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()));
$this
->
level
=
$coll
->
count
()
?
$coll
->
count
()
:
0
;
}
$q
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$q
,
$this
->
getRootValue
());
$coll
=
$q
->
execute
();
$coll
->
delete
();
$first
=
$this
->
getRightValue
()
+
1
;
$delta
=
$this
->
getLeftValue
()
-
$this
->
getRightValue
()
-
1
;
$this
->
shiftRLValues
(
$first
,
$delta
);
return
true
;
}
/**
* sets node's left and right values and save's it
*
* @param int $destLeft node left value
* @param int $destRight node right value
*/
private
function
insertNode
(
$destLeft
=
0
,
$destRight
=
0
,
$destRoot
=
1
)
{
$this
->
setLeftValue
(
$destLeft
);
$this
->
setRightValue
(
$destRight
);
$this
->
setRootValue
(
$destRoot
);
$this
->
record
->
save
();
}
/**
* move node's and its children to location $destLeft and updates rest of tree
*
* @param int $destLeft destination left value
*/
private
function
updateNode
(
$destLeft
)
{
$left
=
$this
->
getLeftValue
();
$right
=
$this
->
getRightValue
();
$treeSize
=
$right
-
$left
+
1
;
$this
->
shiftRLValues
(
$destLeft
,
$treeSize
);
if
(
$left
>=
$destLeft
){
// src was shifted too?
$left
+=
$treeSize
;
$right
+=
$treeSize
;
}
// now there's enough room next to target to move the subtree
$this
->
shiftRLRange
(
$left
,
$right
,
$destLeft
-
$left
);
// correct values after source
$this
->
shiftRLValues
(
$right
+
1
,
-
$treeSize
);
$this
->
record
->
save
();
$this
->
record
->
refresh
();
}
/**
* adds '$delta' to all Left and Right values that are >= '$first'. '$delta' can also be negative.
*
* @param int $first First node to be shifted
* @param int $delta Value to be shifted by, can be negative
*/
private
function
shiftRLValues
(
$first
,
$delta
,
$root_id
=
1
)
{
$qLeft
=
$this
->
record
->
getTable
()
->
createQuery
();
$qRight
=
$this
->
record
->
getTable
()
->
createQuery
();
// TODO: Wrap in transaction
// shift left columns
$qLeft
=
$qLeft
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'lft'
,
"lft +
$delta
"
)
->
where
(
'lft >= ?'
,
$first
);
$qLeft
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qLeft
,
$root_id
);
$resultLeft
=
$qLeft
->
execute
();
// shift right columns
$resultRight
=
$qRight
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'rgt'
,
"rgt +
$delta
"
)
->
where
(
'rgt >= ?'
,
$first
);
$qRight
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qRight
,
$root_id
);
$resultRight
=
$qRight
->
execute
();
}
/**
* adds '$delta' to all Left and Right values that are >= '$first' and <= '$last'.
* '$delta' can also be negative.
*
* @param int $first First node to be shifted (L value)
* @param int $last Last node to be shifted (L value)
* @param int $delta Value to be shifted by, can be negative
*/
private
function
shiftRLRange
(
$first
,
$last
,
$delta
,
$root_id
=
1
)
{
$qLeft
=
$this
->
record
->
getTable
()
->
createQuery
();
$qRight
=
$this
->
record
->
getTable
()
->
createQuery
();
// TODO : Wrap in transaction
return
$this
->
level
;
}
// shift left column values
$qLeft
=
$qLeft
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'lft'
,
"lft +
$delta
"
)
->
where
(
'lft >= ? AND lft <= ?'
,
array
(
$first
,
$last
));
$qLeft
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qLeft
,
$root_id
);
/**
* sets node's level
*
* @param int
*/
public
function
setLevel
(
$level
)
{
$this
->
level
=
$level
;
}
$resultLeft
=
$qLeft
->
execute
();
// shift right column values
$qRight
=
$qRight
->
update
(
$this
->
record
->
getTable
()
->
getComponentName
())
->
set
(
'rgt'
,
"rgt +
$delta
"
)
->
where
(
'rgt >= ? AND rgt <= ?'
,
array
(
$first
,
$last
));
$qRight
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$qRight
,
$root_id
);
$resultRight
=
$qRight
->
execute
();
}
/**
* gets record's left value
*
* @return int
*/
public
function
getLeftValue
()
{
return
$this
->
record
->
get
(
'lft'
);
}
/**
* sets record's left value
*
* @param int
*/
public
function
setLeftValue
(
$lft
)
{
$this
->
record
->
set
(
'lft'
,
$lft
);
}
/**
* gets record's right value
*
* @return int
*/
public
function
getRightValue
()
{
return
$this
->
record
->
get
(
'rgt'
);
}
/**
* sets record's right value
*
* @param int
*/
public
function
setRightValue
(
$rgt
)
{
$this
->
record
->
set
(
'rgt'
,
$rgt
);
}
/**
* gets level (depth) of node in the tree
*
* @return int
*/
public
function
getLevel
()
{
if
(
!
isset
(
$this
->
level
))
{
$q
=
$this
->
record
->
getTable
()
->
createQuery
();
$q
=
$q
->
where
(
'lft < ? AND rgt > ?'
,
array
(
$this
->
getLeftValue
(),
$this
->
getRightValue
()));
$q
=
$this
->
record
->
getTable
()
->
getTree
()
->
returnQueryWithRootId
(
$q
,
$this
->
getRootValue
());
$coll
=
$q
->
execute
();
$this
->
level
=
$coll
->
count
()
?
$coll
->
count
()
:
0
;
}
return
$this
->
level
;
}
/**
* sets node's level
*
* @param int
*/
public
function
setLevel
(
$level
)
{
$this
->
level
=
$level
;
}
/**
* get records root id value
*
*/
public
function
getRootValue
()
{
if
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'has_many_roots'
))
return
$this
->
record
->
get
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'root_column_name'
));
return
1
;
}
/**
* sets records root id value
*
* @param int
*/
public
function
setRootValue
(
$value
)
{
if
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'has_many_roots'
))
$this
->
record
->
set
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'root_column_name'
),
$value
);
}
}
\ No newline at end of file
/**
* get records root id value
*
*/
public
function
getRootValue
()
{
if
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'has_many_roots'
))
return
$this
->
record
->
get
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'root_column_name'
));
return
1
;
}
/**
* sets records root id value
*
* @param int
*/
public
function
setRootValue
(
$value
)
{
if
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'has_many_roots'
))
$this
->
record
->
set
(
$this
->
record
->
getTable
()
->
getTree
()
->
getAttribute
(
'root_column_name'
),
$value
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment