/** * Tree Builder * * Re-sorts the data from from_list() and turns it into two datastructures: * * An array of tree root nodes, with children in the __children__ key * of their respective parents. Thus forming a tree as a nested array. * * A lookup table of id => row, where each item is actually a reference * into the tree. This way we can do quick by-index lookups. * * @param data - array of array('unique_id' => x, 'parent_id' => y, ...data) * @param unique id key * @param parent id key * * @return TreeNode The root node of a tree. */ protected function buildTree($data, $conf) { $nodes = array(); $child_key = $conf['id']; $parent_key = $conf['parent']; $name = $conf['name_key']; $class = $conf['class_name']; // First we create a lookup table of id => object // This lets us build the tree on references which // will in turn allow for quick subtree lookup. foreach ($data as $row) { $id = $row[$child_key]; $nodes[$id] = new $class($row[$name], $row); } $tree = new TreeNode('__root__'); // And now build the actual tree by assigning children foreach ($data as $row) { $parent = $row[$parent_key]; $node = $nodes[$row[$child_key]]; if (isset($nodes[$parent])) { $nodes[$parent]->add($node); } else { $tree->add($node); } } return $tree; }
/** * Recursive iteration over tree-like array. * * @param array $data Data array in the form @code array(array('$keyName'=>$key, '$parentKeyName'=>$parentKey)) @endcode. * @param TreeNode|TreeNodeList $parent Parent object. * @return TreeNodeList */ private static function iterate(array $data, $parent) { foreach ($data as $key => $value) { //Если родителем является TreeNodeList - значит мы на начальном шаге итерации и ключ - пустой, во всех других случаях - ключом является идентификатор узла родителя if ($parent instanceof TreeNodeList) { $parentKey = ''; } else { $parentKey = $parent->getID(); } if ($value[self::$parentKeyName] == $parentKey) { //добавляем узел к родителю $addedNode = $parent->add(new TreeNode($value[self::$keyName])); //удаляем из массива данных unset($data[$key]); //делаем рекурсивный вызов, передавая изменившийся набор данных, и родительский узел self::iterate($data, $addedNode); } } return $parent; }