//$paths is an array of references, in which _every_ item will sit at 'root'
//level, but also as a reference as a child to it's parent.
//initialize location of parentless / root items:
$paths = array('N'=>array());
foreach($items as $item){
//$target is the parent-id, or 'N' if we are a root node
$target = isset($item['enroller_id']) && !empty($item['enroller_id']) ? $item['enroller_id'] :'N';
//if the parent is not yet in the paths array, make an entry for it
if(!isset($paths[$target])) $paths[$target] = array();
//if this item is not yet in the array (the previous statement could
//already have inserted it, make an array(
if(!isset($paths[$item['id']])) $paths[$item['id']] = array();
//add the current item as a reference to it's parent
$paths[$target][$item['id']] = &$paths[$item['id']];
//Setting it as a reference has this consequence:
// when adding an item to the $paths[$id] array, it will
// automatically be added to $paths[$parent][$id], as
// both $paths[$id] & $paths[$parent][$id] point to the same
// location in memory.
// This goes to infinite depth: if $foo is a child of $id, and you
// add a node to it, it will be in
// $paths[$foo] = array($child);
// $paths[$id][[$foo] = array($child);
// $paths[$parent][$id][$foo] = array($child);
//
// Altering an item at any location in paths / the tree will alter it anywhere
// in the paths / tree, unsetting it anywhere only unset the data at that location,
// other locations will still have the same data (and the data will keep
// existing until the last reference is unset())
}
//we are only interested in the 'root' nodes (all other nodes should be subnodes
//in this tree
$tree = $paths['N'];
//remove all unused references in the $paths array
//do remember to do this: cleaning up references is important
unset($paths);
//tree is now an array of 'normal' values (i.e. only 1 reference to each datapoint exists
var_dump($tree);
Don't forget to unset
paths: references can really bite you with difficult to trace errors if you don't take proper care.