/** * Creates a NamedNode tree from an array with path => nodeValue entries. * @param array $tree The collapsed tree: [ $path => $data, ... ] * @return \arc\tree\NamedNode an object tree with parent/children relations */ public static function expand($tree = null) { if (is_object($tree) && isset($tree->childNodes)) { return $tree; //FIXME: should we clone the tree to avoid shared state? } $root = new \arc\tree\NamedNode(); if (!is_array($tree)) { return $root; // empty tree } $previousParent = $root; foreach ($tree as $path => $data) { $previousPath = $previousParent->getPath(); $subPath = \arc\path::diff($previousPath, $path); if ($subPath) { // create missing parent nodes, input tree may be sparsely filled $node = \arc\path::reduce($subPath, function ($previous, $name) { if ($name == '..') { return $previous->parentNode; } return $previous->appendChild($name); }, $previousParent); } else { // means the previousParent is equal to the current path, e.g. the root $node = $previousParent; } $node->nodeValue = $data; $previousParent = $node; } return $root; }
function testMapReduce() { $path = '/a/b/c/'; $result = \arc\path::map($path, function ($entry) { return strtoupper($entry); }); $this->assertTrue($result === '/A/B/C/'); $result = \arc\path::reduce($path, function (&$result, $entry) { return $result . $entry; }); $this->assertTrue($result === 'abc'); $result = \arc\path::map('/', function ($entry) { return 'a'; }); $this->assertTrue($result === '/'); $result = \arc\path::map('frop', function ($entry) { return 'a'; }); $this->assertTrue($result === '/a/'); }
/** * Compile a key-path like '/name/index/index2/' to a variable name like 'name[index][index2]' * @param $path * @param string $root * @return mixed */ public static function compileName($path, $root = '') { return \arc\path::reduce($path, function ($result, $item) { $item = self::unescape($item); return !$result ? $item : $result . '[' . $item . ']'; }, $root); }
/** * Returns the node with the given path, relative to this node. If the path * does not exist, missing nodes will be created automatically. * @param string $path The path to change to * @return \arc\tree\NamedNode The target node corresponding with the given path. */ public function cd($path) { if (\arc\path::isAbsolute($path)) { $node = $this->getRootNode(); } else { $node = $this; } $result = \arc\path::reduce($path, function ($node, $name) { switch ($name) { case '..': return isset($node->parentNode) ? $node->parentNode : $node; break; case '.': case '': return $node; break; default: if (!isset($node->childNodes[$name])) { return $node->appendChild($name); } else { return $node->childNodes[$name]; } break; } }, $node); return $result; }