|
|
@ -199,17 +199,17 @@ class Node implements \ArrayAccess, \Iterator |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Set a child of this node by a dot-separate path. |
|
|
|
* Add/replace a child of this node by a dot-separated path. |
|
|
|
* |
|
|
|
* Each element of the path can either be a node name or a numeric |
|
|
|
* index representing the offset into an array |
|
|
|
* |
|
|
|
* @todo will explode if you try to write using a numeric index to an array |
|
|
|
* element that doesn't exist |
|
|
|
* @param string $path |
|
|
|
* @param Node $node |
|
|
|
* @param string $path |
|
|
|
* @param Node $node |
|
|
|
* @return void |
|
|
|
*/ |
|
|
|
public function addChildUnderPath(string $path, Node $node): void |
|
|
|
public function setChildByPath(string $path, Node $node): void |
|
|
|
{ |
|
|
|
$path = explode('.', $path); |
|
|
|
$current = $this; |
|
|
@ -229,17 +229,24 @@ class Node implements \ArrayAccess, \Iterator |
|
|
|
{ |
|
|
|
$next_node = new Node($current, $next); |
|
|
|
$current->addChild($next_node); |
|
|
|
$current = $next_node; |
|
|
|
} |
|
|
|
$current = $next_node; |
|
|
|
} |
|
|
|
|
|
|
|
if (!isset($current)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
throw new \Exception('Cannot write to non-existent array index by path'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
$current->addChild($node); |
|
|
|
// Replace current with the passed in node |
|
|
|
$current->remove(); |
|
|
|
$current->getParent()->addChild($node); |
|
|
|
$node->setParent($current->getParent()); |
|
|
|
if ($current->hasName()) |
|
|
|
{ |
|
|
|
$node->setName($current->getName()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -343,6 +350,72 @@ class Node implements \ArrayAccess, \Iterator |
|
|
|
$this->getParent()->removeChild($this); |
|
|
|
} |
|
|
|
|
|
|
|
public static function toPhp(Node $node) |
|
|
|
{ |
|
|
|
if ($node instanceof NodeValue) |
|
|
|
{ |
|
|
|
return $node->getValue(); |
|
|
|
} |
|
|
|
elseif ($node->isArray()) |
|
|
|
{ |
|
|
|
$result = []; |
|
|
|
foreach ($node as $child) |
|
|
|
{ |
|
|
|
$result[] = static::toPhp($child); |
|
|
|
} |
|
|
|
return $result; |
|
|
|
} |
|
|
|
elseif ($node->isMap()) |
|
|
|
{ |
|
|
|
$result = []; |
|
|
|
foreach ($node as $child) |
|
|
|
{ |
|
|
|
$result[$child->getName()] = static::toPhp($child); |
|
|
|
} |
|
|
|
return $result; |
|
|
|
} |
|
|
|
|
|
|
|
throw new \Exception('Cannot convert from DOM node'); |
|
|
|
} |
|
|
|
|
|
|
|
public static function fromPhp($value): Node |
|
|
|
{ |
|
|
|
if (is_scalar($value)) |
|
|
|
{ |
|
|
|
return new NodeValue(null, null, $value); |
|
|
|
} |
|
|
|
elseif (is_array($value)) |
|
|
|
{ |
|
|
|
$contains_only_numeric_keys = array_reduce(array_keys($value), static function($carry, $item) { |
|
|
|
return $carry && is_numeric($item); |
|
|
|
}, true); |
|
|
|
|
|
|
|
if ($contains_only_numeric_keys) |
|
|
|
{ |
|
|
|
$node = new Node(null, null); |
|
|
|
foreach ($value as $item) |
|
|
|
{ |
|
|
|
$child = static::fromPhp($item); |
|
|
|
$child->setParent($node); |
|
|
|
$node->addChild($child); |
|
|
|
} |
|
|
|
return $node; |
|
|
|
} |
|
|
|
|
|
|
|
$node = new Node(null, null); |
|
|
|
foreach ($value as $key => $item) |
|
|
|
{ |
|
|
|
$child = static::fromPhp($item); |
|
|
|
$child->setName($key); |
|
|
|
$child->setParent($node); |
|
|
|
$node->addChild($child); |
|
|
|
} |
|
|
|
return $node; |
|
|
|
} |
|
|
|
|
|
|
|
throw new \Exception('Cannot convert passed value into DOM nodes'); |
|
|
|
} |
|
|
|
|
|
|
|
// ArrayAccess |
|
|
|
|
|
|
|
public function offsetExists($offset): bool |
|
|
|