ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
ilMaterializedPathTree Class Reference

Base class for materialize path based trees Based on implementation of Werner Randelshofer. More...

+ Inheritance diagram for ilMaterializedPathTree:
+ Collaboration diagram for ilMaterializedPathTree:

Public Member Functions

 __construct (ilTree $a_tree)
 Constructor.
 getTree ()
 Get tree object.
 getSubTreeIds ($a_node_id)
 Get subtree ids.
 getRelation ($a_node_a, $a_node_b)
 Get relation of two nodes.
 getSubTreeQuery ($a_node, $a_types= '', $a_force_join_reference=true, $a_fields=array())
 Get subtree query.
 getPathIds ($a_endnode, $a_startnode=0)
 Get path ids.
 insertNode ($a_node_id, $a_parent_id, $a_pos)
 Insert new node under parent node.
 deleteTree ($a_node_id)
 Delete a subtree.
 moveToTrash ($a_node_id)
 Move subtree to trash.
 moveTree ($a_source_id, $a_target_id, $a_position)
 move source subtree to target node
 getSubtreeInfo ($a_endnode_id)
 Get subtree info lft, rgt, path, child, type.

Static Public Member Functions

static createFromParentReleation ()

Protected Member Functions

 getMaximumPossibleDepth ()
 Get maximum possible depth.

Static Private Member Functions

static createMaterializedPath ($parent, $parentPath)

Private Attributes

 $maximum_possible_depth = 100
 $tree = NULL

Detailed Description

Base class for materialize path based trees Based on implementation of Werner Randelshofer.

Author
Stefan Meyer meyer.nosp@m.@lei.nosp@m.fos.c.nosp@m.om
Version
$Id$

Definition at line 16 of file class.ilMaterializedPathTree.php.

Constructor & Destructor Documentation

ilMaterializedPathTree::__construct ( ilTree  $a_tree)

Constructor.

Parameters
ilTree$tree

Definition at line 25 of file class.ilMaterializedPathTree.php.

{
$this->tree = $a_tree;
}

Member Function Documentation

static ilMaterializedPathTree::createFromParentReleation ( )
static

Definition at line 456 of file class.ilMaterializedPathTree.php.

References $ilDB, $row, $success, and createMaterializedPath().

Referenced by ilSetupGUI\switchTree().

{
global $ilDB;
$r = $ilDB->queryF('SELECT DISTINCT * FROM tree WHERE parent = %s', array('integer'), array(0));
while ($row = $ilDB->fetchAssoc($r))
{
if ($success !== true)
{
}
}
}

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static ilMaterializedPathTree::createMaterializedPath (   $parent,
  $parentPath 
)
staticprivate

Definition at line 473 of file class.ilMaterializedPathTree.php.

References $ilDB, and $row.

Referenced by createFromParentReleation().

{
global $ilDB;
$q = ' UPDATE tree
SET path = CONCAT(COALESCE(' . $ilDB->quote($parentPath, 'text') . ', \'\'), COALESCE(child, \'\'))
WHERE parent = %s';
$r = $ilDB->manipulateF($q, array('integer'), array($parent));
$r = $ilDB->queryF('SELECT child FROM tree WHERE parent = %s', array('integer'), array($parent));
while ($row = $ilDB->fetchAssoc($r))
{
self::createMaterializedPath($row['child'], $parentPath . $row['child'] . '.');
}
return true;
}

+ Here is the caller graph for this function:

ilMaterializedPathTree::deleteTree (   $a_node_id)

Delete a subtree.

Parameters
int$a_node_id

Implements ilTreeImplementation.

Definition at line 273 of file class.ilMaterializedPathTree.php.

References $ilDB, $query, and getTree().

{
global $ilDB;
$a_node = $this->getTree()->getNodeData($a_node_id);
$query = 'DELETE FROM '.$this->getTree()->getTreeTable().' '.
'WHERE path BETWEEN '.$ilDB->quote($a_node['path'],'text').' '.
'AND '.$ilDB->quote($a_node['path'].'.Z','text').' '.
'AND '.$this->getTree()->getTreePk().' = '.$ilDB->quote($a_node[$this->getTree()->getTreePk()]);
$ilDB->manipulate($query);
return true;
}

+ Here is the call graph for this function:

ilMaterializedPathTree::getMaximumPossibleDepth ( )
protected

Get maximum possible depth.

Returns
type

Definition at line 35 of file class.ilMaterializedPathTree.php.

References $maximum_possible_depth.

ilMaterializedPathTree::getPathIds (   $a_endnode,
  $a_startnode = 0 
)

Get path ids.

Parameters
int$a_endnode
int$a_startnode

Implements ilTreeImplementation.

Definition at line 169 of file class.ilMaterializedPathTree.php.

References $ilDB, $path, $query, $res, $row, and getTree().

{
global $ilDB;
$ilDB->setLimit(1);
$query = 'SELECT path FROM ' . $this->getTree()->getTreeTable() .' '.
'WHERE child = '. $ilDB->quote($a_endnode,'integer').' ';
$res = $ilDB->query($query);
$path = null;
while ($row = $ilDB->fetchAssoc($res))
{
$path = $row['path'];
}
$pathIds = explode('.', $path);
if ($a_startnode != 0)
{
while (count($pathIds) > 0 && $pathIds[0] != $a_startnode)
{
array_shift($pathIds);
}
}
return $pathIds;
}

+ Here is the call graph for this function:

ilMaterializedPathTree::getRelation (   $a_node_a,
  $a_node_b 
)

Get relation of two nodes.

Parameters
type$a_node_a
type$a_node_b

Implements ilTreeImplementation.

Definition at line 82 of file class.ilMaterializedPathTree.php.

References $GLOBALS, ilTree\RELATION_CHILD, ilTree\RELATION_EQUALS, ilTree\RELATION_NONE, ilTree\RELATION_PARENT, and ilTree\RELATION_SIBLING.

{
if($a_node_a['child'] == $a_node_b['child'])
{
$GLOBALS['ilLog']->write(__METHOD__.': EQUALS');
}
if(stristr($a_node_a['path'], $a_node_b['path']))
{
$GLOBALS['ilLog']->write(__METHOD__.': CHILD');
}
if(stristr($a_node_b['path'], $a_node_a['path']))
{
$GLOBALS['ilLog']->write(__METHOD__.': PARENT');
}
$path_a = substr($a_node_a['path'],0,strrpos($a_node_a['path'],'.'));
$path_b = substr($a_node_b['path'],0,strrpos($a_node_b['path'],'.'));
$GLOBALS['ilLog']->write(__METHOD__.': Comparing '.$path_a .' '. 'with '.$path_b);
if($a_node_a['path'] and (strcmp($path_a,$path_b) === 0))
{
$GLOBALS['ilLog']->write(__METHOD__.': SIBLING');
}
$GLOBALS['ilLog']->write(__METHOD__.': NONE');
}
ilMaterializedPathTree::getSubTreeIds (   $a_node_id)

Get subtree ids.

Parameters
type$a_node_id

Implements ilTreeImplementation.

Definition at line 53 of file class.ilMaterializedPathTree.php.

References $ilDB, $query, $res, $row, and getTree().

{
global $ilDB;
$node = $this->getTree()->getNodeTreeData($a_node_id);
$query = 'SELECT child FROM '.$this->getTree()->getTreeTable().' '.
'WHERE path BETWEEN '.
$ilDB->quote($node['path'], 'text').' AND '.
$ilDB->quote($node['path'].'.Z', 'text').' '.
'AND child != %s '.
'AND '.$this->getTree()->getTreePk().' = %s';
$res = $ilDB->queryF(
array('integer', 'integer'),
array($a_node_id, $this->getTree()->getTreeId())
);
while($row = $ilDB->fetchAssoc($res))
{
$childs[] = $row['child'];
}
return $childs ? $childs : array();
}

+ Here is the call graph for this function:

ilMaterializedPathTree::getSubtreeInfo (   $a_endnode_id)

Get subtree info lft, rgt, path, child, type.

Returns
array

Implements ilTreeImplementation.

Definition at line 491 of file class.ilMaterializedPathTree.php.

References $ilDB, $query, $res, $row, DB_FETCHMODE_OBJECT, and getTree().

{
global $ilDB;
// This is an optimization without the temporary tables become too big for our system.
// The idea is to use a subquery to join and filter the trees, and only the result
// is joined to obj_reference and obj_data.
$query = "SELECT t2.child child, type, t2.path path " .
"FROM " . $this->getTree()->getTreeTable() . " t1 " .
"JOIN " . $this->getTree()->getTreeTable() . " t2 ON (t2.path BETWEEN t1.path AND CONCAT(t1.path, '.Z')) " .
"JOIN " . $this->getTree()->getTableReference() . " obr ON t2.child = obr.ref_id " .
"JOIN " . $this->getTree()->getObjectDataTable() . " obd ON obr.obj_id = obd.obj_id " .
"WHERE t1.child = " . $ilDB->quote($a_endnode_id, 'integer') . " " .
"AND t1." . $this->getTree()->getTreePk() . " = " . $ilDB->quote($this->getTree()->getTreeId(), 'integer') . " " .
"AND t2." . $this->getTree()->getTreePk() . " = " . $ilDB->quote($this->getTree()->getTreeId(), 'integer') . " " .
"ORDER BY t2.path";
$res = $ilDB->query($query);
$nodes = array();
while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
{
#$nodes[$row->child]['lft'] = $row->lft;
#$nodes[$row->child]['rgt'] = $row->rgt;
$nodes[$row->child]['child'] = $row->child;
$nodes[$row->child]['type'] = $row->type;
$nodes[$row->child]['path'] = $row->path;
}
$depth_first_compare = function($a, $b)
{
$a_exploded = explode('.', $a['path']);
#$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($a_exploded,TRUE));
$b_exploded = explode('.', $b['path']);
$a_padded = '';
foreach($a_exploded as $num)
{
$a_padded .= (str_pad((string) $num, 14,'0', STR_PAD_LEFT));
}
$b_padded = '';
foreach($b_exploded as $num)
{
$b_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
}
#$GLOBALS['ilLog']->write(__METHOD__.': '.$a_padded);
#$GLOBALS['ilLog']->write(__METHOD__.': '.$a_padded);
return strcasecmp($a_padded, $b_padded);
};
#$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($nodes,TRUE));
uasort($nodes,$depth_first_compare);
#$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($nodes,TRUE));
return (array) $nodes;
}

+ Here is the call graph for this function:

ilMaterializedPathTree::getSubTreeQuery (   $a_node,
  $a_types = '',
  $a_force_join_reference = true,
  $a_fields = array() 
)

Get subtree query.

Parameters
type$a_node
type$a_types

Implements ilTreeImplementation.

Definition at line 119 of file class.ilMaterializedPathTree.php.

References $ilDB, $query, and getTree().

{
global $ilDB;
$type_str = '';
if(is_array($a_types))
{
if($a_types)
{
$type_str = "AND ".$ilDB->in($this->getTree()->getObjectDataTable().".type", $a_types, false, "text");
}
}
else if(strlen($a_types))
{
$type_str = "AND ".$this->getTree()->getObjectDataTable().".type = ".$ilDB->quote($a_types, "text");
}
$join = '';
if($type_str or $a_force_join_reference)
{
$join = $this->getTree()->buildJoin();
}
$fields = '* ';
if(count($a_fields))
{
$fields = implode(',',$a_fields);
}
// @todo order by
$query = 'SELECT '.
$fields.' '.
'FROM '.$this->getTree()->getTreeTable().' '.
$join.' '.
'WHERE '.$this->getTree()->getTreeTable().'.path '.
'BETWEEN '.
$ilDB->quote($a_node['path'],'text').' AND '.
$ilDB->quote($a_node['path'].'.Z','text').' '.
'AND '.$this->getTree()->getTreeTable().'.'.$this->getTree()->getTreePk().' = '.$ilDB->quote($this->getTree()->getTreeId(),'integer').' '.
$type_str.' '.
'ORDER BY '.$this->getTree()->getTreeTable().'.path';
return $query;
}

+ Here is the call graph for this function:

ilMaterializedPathTree::getTree ( )

Get tree object.

Returns
ilTree $tree

Definition at line 44 of file class.ilMaterializedPathTree.php.

References $tree.

Referenced by deleteTree(), getPathIds(), getSubTreeIds(), getSubtreeInfo(), getSubTreeQuery(), insertNode(), moveToTrash(), and moveTree().

{
return $this->tree;
}

+ Here is the caller graph for this function:

ilMaterializedPathTree::insertNode (   $a_node_id,
  $a_parent_id,
  $a_pos 
)

Insert new node under parent node.

Parameters
type$a_node_id
type$a_parent_id
type$a_pos

Implements ilTreeImplementation.

Definition at line 202 of file class.ilMaterializedPathTree.php.

References $GLOBALS, $ilDB, $res, getTree(), and ilDB\LOCK_WRITE.

{
global $ilDB;
// LOCKED ###########################################################
if ($this->getTree()->__isMainTree())
{
$ilDB->lockTables(
array(
0 => array('name' => 'tree', 'type' => ilDB::LOCK_WRITE)));
}
// get path and depth of parent
$ilDB->setLimit(1);
$res = $ilDB->queryF(
'SELECT parent, depth, path FROM ' . $this->getTree()->getTreeTable() . ' ' .
'WHERE child = %s '. ' '.
'AND ' . $this->getTree()->getTreePk() . ' = %s', array('integer', 'integer'),
array($a_parent_id, $this->getTree()->getTreeId()));
$r = $ilDB->fetchObject($res);
if ($r->parent == NULL)
{
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
$GLOBALS['ilLog']->logStack();
throw new ilInvalidTreeStructureException('Parent node not found in tree');
}
if ($r->depth >= $this->getMaximumPossibleDepth())
{
// LOCKED ###########################################################
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
$GLOBALS['ilLog']->logStack();
throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
}
$parentPath = $r->path;
$depth = $r->depth + 1;
$lft = 0;
$rgt = 0;
$ilDB->insert($this->getTree()->getTreeTable(), array($this->getTree()->getTreePk() => array('integer', $this->getTree()->getTreeId()),
'child' => array('integer', $a_node_id),
'parent' => array('integer', $a_parent_id),
'lft' => array('integer', $lft),
'rgt' => array('integer', $rgt),
'depth' => array('integer', $depth),
'path' => array('text', $parentPath . "." . $a_node_id)));
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
}

+ Here is the call graph for this function:

ilMaterializedPathTree::moveToTrash (   $a_node_id)

Move subtree to trash.

Parameters
type$a_node_id

Implements ilTreeImplementation.

Definition at line 291 of file class.ilMaterializedPathTree.php.

References $ilDB, getTree(), and ilDB\LOCK_WRITE.

{
global $ilDB;
// LOCKED ###########################################################
if ($this->getTree()->__isMainTree())
{
$ilDB->lockTables(
array(
0 => array('name' => 'tree', 'type' => ilDB::LOCK_WRITE)));
}
try
{
$node = $this->getTree()->getNodeTreeData($a_node_id);
}
catch(Exception $e)
{
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
throw $e;
}
// Set the nodes deleted (negative tree id)
$ilDB->manipulateF('
UPDATE ' . $this->getTree()->getTreeTable().' '.
'SET tree = %s' .' '.
'WHERE ' . $this->getTree()->getTreePk() . ' = %s ' .
'AND path BETWEEN %s AND %s',
array('integer', 'integer', 'text', 'text'),
array(-$a_node_id, $this->getTree()->getTreeId(), $node['path'], $node['path'] . '.Z'));
// LOCKED ###########################################################
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
return true;
}

+ Here is the call graph for this function:

ilMaterializedPathTree::moveTree (   $a_source_id,
  $a_target_id,
  $a_position 
)

move source subtree to target node

Parameters
type$a_source_id
type$a_target_id
type$a_position

Implements ilTreeImplementation.

Definition at line 340 of file class.ilMaterializedPathTree.php.

References $GLOBALS, $ilDB, $query, $res, $row, getTree(), and ilDB\LOCK_WRITE.

{
global $ilDB;
if ($this->getTree()->__isMainTree())
{
$ilDB->lockTables(
array(
0 => array('name' => 'tree', 'type' => ilDB::LOCK_WRITE)));
}
// Receive node infos for source and target
$ilDB->setLimit(2);
$res = $ilDB->query(
'SELECT depth, child, parent, path FROM ' . $this->getTree()->getTreeTable() . ' '.
'WHERE ' . $ilDB->in('child', array($a_source_id, $a_target_id), false, 'integer') . ' '.
'AND tree = ' . $ilDB->quote($this->getTree()->getTreeId(), 'integer')
);
// Check in tree
if ($ilDB->numRows($res) != 2)
{
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
$GLOBALS['ilLog']->logStack();
$GLOBALS['ilLog']->write(__METHOD__.': Objects not found in tree');
throw new InvalidArgumentException('Error moving subtree');
}
while ($row = $ilDB->fetchObject($res))
{
if ($row->child == $a_source_id)
{
$source_path = $row->path;
$source_depth = $row->depth;
$source_parent = $row->parent;
}
else
{
$target_path = $row->path;
$target_depth = $row->depth;
}
}
if ($target_depth >= $source_depth)
{
// We move nodes deeper into the tree. Therefore we need to
// check whether we might exceed the maximal path length.
// We use FOR UPDATE here, because we don't want anyone to
// insert new nodes while we move the subtree.
$res = $ilDB->queryF(
'SELECT MAX(depth) max_depth '.
'FROM ' . $this->getTree()->getTreeTable() . ' '.
'WHERE path BETWEEN %s AND %s'.' '.
'AND tree = %s ',
array('text', 'text', 'integer'), array($source_path, $source_path . '.Z', $this->getTree()->getTreeId()));
$row = $ilDB->fetchObject($res);
if ($row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth())
{
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
$GLOBALS['ilLog']->logStack();
$GLOBALS['ilLog']->write(__METHOD__.': Objects not found in tree');
throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
}
}
// Check target not child of source
if (substr($target_path . '.', 0, strlen($source_path) . '.') == $source_path . '.')
{
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
$GLOBALS['ilLog']->logStack();
$GLOBALS['ilLog']->write(__METHOD__.': Target is child of source');
throw new ilInvalidArgumentException('Error moving subtree: target is child of source');
}
$depth_diff = $target_depth - $source_depth + 1;
// move subtree:
$query = '
UPDATE ' . $this->getTree()->getTreeTable() . '
SET parent = CASE WHEN parent = ' . $ilDB->quote($source_parent, 'integer') . '
THEN ' . $ilDB->quote($a_target_id, 'integer') . '
ELSE parent END,
path = ' . $ilDB->concat(array(
array($ilDB->quote($target_path, 'text'), 'text'),
array($ilDB->substr('path', strrpos('.' . $source_path, '.')), 'text'))) . ' ,
depth = depth + ' . $ilDB->quote($depth_diff, 'integer') . '
WHERE path BETWEEN ' . $ilDB->quote($source_path, 'text') . '
AND ' . $ilDB->quote($source_path . '.Z', 'text') . '
AND tree = ' . $ilDB->quote($this->getTree()->getTreeId(), 'integer');
$GLOBALS['ilLog']->write(__METHOD__.': query is ' . $query);
$ilDB->manipulate($query);
if ($this->getTree()->__isMainTree())
{
$ilDB->unlockTables();
}
return true;
}

+ Here is the call graph for this function:

Field Documentation

ilMaterializedPathTree::$maximum_possible_depth = 100
private

Definition at line 18 of file class.ilMaterializedPathTree.php.

Referenced by getMaximumPossibleDepth().

ilMaterializedPathTree::$tree = NULL
private

Definition at line 19 of file class.ilMaterializedPathTree.php.

Referenced by getTree().


The documentation for this class was generated from the following file: