embed-8.x-1.x-dev/src/DomHelperTrait.php
src/DomHelperTrait.php
<?php
declare(strict_types=1);
namespace Drupal\embed;
use Drupal\Component\Utility\Html;
/**
* Wrapper methods for manipulating DOM entries.
*
* This utility trait should only be used in application-level code, such as
* classes that would implement ContainerInjectionInterface. Services registered
* in the Container should not use this trait but inject the appropriate service
* directly for easier testing.
*/
trait DomHelperTrait {
/**
* Rename a DOMNode tag.
*
* @param \DOMNode $node
* A DOMElement object.
* @param string $name
* The new tag name.
*/
protected function changeNodeName(\DOMNode &$node, string $name = 'div'): void {
if ($node->nodeName != $name) {
/** @var \DOMElement $replacement_node */
$replacement_node = $node->ownerDocument->createElement($name);
// Copy all children of the original node to the new node.
if ($node->childNodes->length) {
foreach ($node->childNodes as $child) {
$child = $replacement_node->ownerDocument->importNode($child, TRUE);
$replacement_node->appendChild($child);
}
}
// Copy all attributes of the original node to the new node.
if ($node->attributes->length) {
foreach ($node->attributes as $attribute) {
$replacement_node->setAttribute($attribute->nodeName, $attribute->nodeValue);
}
}
$node->parentNode->replaceChild($replacement_node, $node);
$node = $replacement_node;
}
}
/**
* Set the contents of a DOMNode.
*
* @param \DOMNode $node
* A DOMNode object.
* @param string $content
* The text or HTML that will replace the contents of $node.
*/
protected function setNodeContent(\DOMNode $node, string $content): void {
// Remove all children of the DOMNode.
while ($node->hasChildNodes()) {
$node->removeChild($node->firstChild);
}
if (strlen($content)) {
// Load the contents into a new DOMDocument and retrieve the elements.
$replacement_nodes = Html::load($content)->getElementsByTagName('body')->item(0);
// Finally, import and append the contents to the original node.
foreach ($replacement_nodes->childNodes as $replacement_node) {
$replacement_node = $node->ownerDocument->importNode($replacement_node, TRUE);
$node->appendChild($replacement_node);
}
}
}
/**
* Replace the contents of a DOMNode.
*
* @param \DOMNode $node
* A DOMNode object.
* @param string $content
* The text or HTML that will replace the contents of $node.
*/
protected function replaceNodeContent(\DOMNode $node, string $content): void {
if (strlen($content)) {
// Load the content into a new DOMDocument and retrieve the DOM nodes.
$replacement_nodes = Html::load($content)->getElementsByTagName('body')
->item(0)
->childNodes;
}
else {
$replacement_nodes = [$node->ownerDocument->createTextNode('')];
}
foreach ($replacement_nodes as $replacement_node) {
// Import the replacement node from the new DOMDocument into the original
// one, importing also the child nodes of the replacement node.
$replacement_node = $node->ownerDocument->importNode($replacement_node, TRUE);
$node->parentNode->insertBefore($replacement_node, $node);
}
$node->parentNode->removeChild($node);
}
/**
* Convert the attributes on a DOMNode object to an array.
*
* This will also un-serialize any attribute values stored as JSON.
*
* @param \DOMNode $node
* A DOMNode object.
*
* @return array
* The attributes as an associative array, keyed by the attribute names.
*/
public function getNodeAttributesAsArray(\DOMNode $node): array {
$return = [];
// Convert the data attributes to the context array.
foreach ($node->attributes as $attribute) {
$key = $attribute->nodeName;
$return[$key] = $attribute->nodeValue;
// Check for JSON-encoded attributes.
$data = json_decode($return[$key], TRUE, 10);
if ($data !== NULL && json_last_error() === JSON_ERROR_NONE) {
$return[$key] = $data;
}
}
return $return;
}
}
