Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
DomMerger.php
Go to the documentation of this file.
1 <?php
7 
10 
14 class DomMerger implements DomMergerInterface
15 {
19  const ERROR_FORMAT_DEFAULT = "Message: %message%\nLine: %line%\n";
20 
24  private $validationState;
25 
31  protected $schemaFilePath;
32 
38  protected $domDocument;
39 
45  protected $idAttributes = [];
46 
52  protected $contextXPath = [];
53 
60 
64  private $schema;
65 
80  public function __construct(
81  ValidationStateInterface $validationState,
82  $schema,
84  array $contextXPath = [],
85  array $idAttributes = []
86  ) {
87  $this->validationState = $validationState;
88  $this->schema = $schema;
89  $this->isMergeSimpleXMLElement = $isMergeSimpleXMLElement;
90  $this->contextXPath = $contextXPath;
91  $this->idAttributes = $idAttributes;
92  }
93 
100  protected function isIdAttribute($attributeName)
101  {
102  return in_array($attributeName, $this->idAttributes);
103  }
104 
111  protected function isMergeContext($xPath)
112  {
113  foreach ($this->contextXPath as $context) {
114  if (strpos($xPath, $context) === 0) {
115  return true;
116  }
117  }
118  return false;
119  }
120 
127  protected function isContextXPath(array $xPath)
128  {
129  return count(array_intersect($xPath, $this->contextXPath)) === count($xPath);
130  }
131 
139  protected function mergeAttributes(\DOMElement $baseNode, \DOMNode $mergeNode)
140  {
141  foreach ($mergeNode->attributes as $name => $attribute) {
142  $baseNode->setAttribute($name, $attribute->value);
143  }
144  }
145 
152  protected function createXPath(\DOMNode $node)
153  {
154  $parentXPath = '';
155  $currentXPath = $node->getNodePath();
156  if ($node->parentNode !== null && !$node->isSameNode($node->parentNode)) {
157  $parentXPath = $this->createXPath($node->parentNode);
158  $pathParts = explode('/', $currentXPath);
159  $currentXPath = '/' . end($pathParts);
160  }
161  $attributesXPath = '';
162  if ($node->hasAttributes()) {
163  $attributes = [];
164  foreach ($node->attributes as $name => $attribute) {
165  if ($this->isIdAttribute($name)) {
166  $attributes[] = sprintf('@%s="%s"', $name, $attribute->value);
167  break;
168  }
169  }
170  if (!empty($attributes)) {
171  if (substr($currentXPath, -1) === ']') {
172  $currentXPath = substr($currentXPath, 0, strrpos($currentXPath, '['));
173  }
174  $attributesXPath = '[' . implode(' and ', $attributes) . ']';
175  }
176  }
177  return '/' . trim($parentXPath . $currentXPath . $attributesXPath, '/');
178  }
179 
191  protected function nestedMerge(\DOMXPath $rootDomXPath, \DOMNodeList $insertedNodes, \DOMNode $contextNode)
192  {
193  for ($i = 0, $iLength = $insertedNodes->length; $i < $iLength; ++$i) {
194  $insertedItem = $insertedNodes->item($i);
195  switch ($insertedItem->nodeType) {
196  case XML_TEXT_NODE:
197  case XML_COMMENT_NODE:
198  case XML_CDATA_SECTION_NODE:
199  if (trim($insertedItem->textContent) !== '') {
200  $this->insertBefore($contextNode, $insertedItem);
201  }
202  break;
203  default:
204  $insertedXPath = $this->createXPath($insertedItem);
205  $rootMatchList = $rootDomXPath->query($insertedXPath, $contextNode);
206  $jLength = $rootMatchList->length;
207  if ($jLength > 0) {
208  for ($j = 0; $j < $jLength; ++$j) {
209  $rootItem = $rootMatchList->item($j);
210  $rootItemXPath = $this->createXPath($rootItem);
211  if ($this->isMergeContext($insertedXPath)) {
212  if ($this->isTextNode($insertedItem) && $this->isTextNode($rootItem)) {
213  $rootItem->nodeValue = $insertedItem->nodeValue;
214  } elseif (!$this->isContextXPath([$rootItemXPath, $insertedXPath])
215  && !$this->hasIdAttribute($rootItem)
216  && !$this->hasIdAttribute($insertedItem)
217  ) {
218  if ($this->isMergeSimpleXMLElement) {
219  $this->nestedMerge($rootDomXPath, $insertedItem->childNodes, $rootItem);
220  $this->mergeAttributes($rootItem, $insertedItem);
221  } else {
222  $this->appendChild($contextNode, $insertedItem);
223  }
224  } else {
225  $this->nestedMerge($rootDomXPath, $insertedItem->childNodes, $rootItem);
226  $this->mergeAttributes($rootItem, $insertedItem);
227  }
228  } else {
229  $this->appendChild($contextNode, $insertedItem);
230  }
231  }
232  } else {
233  $this->appendChild($contextNode, $insertedItem);
234  }
235  break;
236  }
237  }
238  }
239 
247  protected function appendChild(\DOMNode $parentNode, \DOMNode $childNode)
248  {
249  $importNode = $this->getDom()->importNode($childNode, true);
250  $parentNode->appendChild($importNode);
251  }
252 
260  protected function insertBefore(\DOMNode $parentNode, \DOMNode $childNode)
261  {
262  $importNode = $this->getDom()->importNode($childNode, true);
263  $parentNode->insertBefore($importNode);
264  }
265 
272  protected function isTextNode(\DOMNode $node)
273  {
274  return $node->childNodes->length == 1 && $node->childNodes->item(0) instanceof \DOMText;
275  }
276 
284  protected function hasIdAttribute(\DOMNode $node)
285  {
286  if (!$node->hasAttributes()) {
287  return false;
288  }
289 
290  foreach ($node->attributes as $name => $attribute) {
291  if (in_array($name, $this->idAttributes)) {
292  return true;
293  }
294  }
295 
296  return false;
297  }
298 
311  public function mergeNode(\DOMElement $node)
312  {
313  $parentDoom = $this->getDom();
314  $this->nestedMerge(new \DOMXPath($parentDoom), $node->childNodes, $parentDoom->documentElement);
315  }
316 
324  public function createDomDocument($xml)
325  {
326  $domDocument = new \DOMDocument();
327  $domDocument->loadXML($xml);
328  if ($this->validationState->isValidationRequired() && $this->schema) {
330  if (count($errors)) {
331  throw new \Magento\Framework\Exception\LocalizedException(
332  new \Magento\Framework\Phrase(implode("\n", $errors))
333  );
334  }
335  }
336 
337  return $domDocument;
338  }
339 
348  protected function validateDomDocument(\DOMDocument $domDocument, $schema = null)
349  {
350  $schema = $schema !== null ? $schema : $this->schema;
351  libxml_use_internal_errors(true);
352  try {
354  } catch (\Exception $exception) {
355  libxml_use_internal_errors(false);
356  throw $exception;
357  }
358  libxml_use_internal_errors(false);
359 
360  return $errors;
361  }
362 
370  protected function renderErrorMessage(\LibXMLError $errorInfo)
371  {
372  $result = static::ERROR_FORMAT_DEFAULT;
373  foreach ($errorInfo as $field => $value) {
374  $result = str_replace('%' . $field . '%', trim((string)$value), $result);
375  }
376  if (strpos($result, '%') !== false) {
377  throw new \Magento\Framework\Exception\LocalizedException(
378  new \Magento\Framework\Phrase(
379  'Error format "' . static::ERROR_FORMAT_DEFAULT . '" contains unsupported placeholders.'
380  )
381  );
382  }
383 
384  return $result;
385  }
386 
393  public function merge($xml)
394  {
395  if (!isset($this->domDocument)) {
396  $this->domDocument = $this->createDomDocument($xml);
397  } else {
398  $this->mergeNode($this->createDomDocument($xml)->documentElement);
399  }
400  }
401 
408  public function getDom()
409  {
410  if (!isset($this->domDocument)) {
411  throw new \Magento\Framework\Exception\LocalizedException(
412  new \Magento\Framework\Phrase('Object DOMDocument should be created.')
413  );
414  }
415 
416  return $this->domDocument;
417  }
418 
425  public function setDom(\DOMDocument $domDocument)
426  {
427  $this->domDocument = $domDocument;
428  }
429 
435  public function unsetDom()
436  {
437  unset($this->domDocument);
438  }
439 
446  public function validate($schemaFilePath = null)
447  {
448  if (!$this->validationState->isValidationRequired()) {
449  return [];
450  }
451  return $this->validateDomDocument($this->getDom(), $schemaFilePath);
452  }
453 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
static validateDomDocument(\DOMDocument $dom, $schema, $errorFormat=self::ERROR_FORMAT_DEFAULT)
Definition: Dom.php:301
appendChild(\DOMNode $parentNode, \DOMNode $childNode)
Definition: DomMerger.php:247
$value
Definition: gender.phtml:16
nestedMerge(\DOMXPath $rootDomXPath, \DOMNodeList $insertedNodes, \DOMNode $contextNode)
Definition: DomMerger.php:191
mergeAttributes(\DOMElement $baseNode, \DOMNode $mergeNode)
Definition: DomMerger.php:139
$attributes
Definition: matrix.phtml:13
__construct(ValidationStateInterface $validationState, $schema, $isMergeSimpleXMLElement=false, array $contextXPath=[], array $idAttributes=[])
Definition: DomMerger.php:80
$i
Definition: gallery.phtml:31
insertBefore(\DOMNode $parentNode, \DOMNode $childNode)
Definition: DomMerger.php:260
$errors
Definition: overview.phtml:9
validateDomDocument(\DOMDocument $domDocument, $schema=null)
Definition: DomMerger.php:348
if(!isset($_GET['name'])) $name
Definition: log.php:14