Flat.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Config\Converter\Dom;
  7. use Magento\Framework\Config\Dom\ArrayNodeConfig;
  8. /**
  9. * Universal converter of any XML data to an array representation with no data loss
  10. *
  11. * @api
  12. * @since 100.0.2
  13. */
  14. class Flat
  15. {
  16. /**
  17. * @var ArrayNodeConfig
  18. */
  19. protected $arrayNodeConfig;
  20. /**
  21. * Constructor
  22. *
  23. * @param ArrayNodeConfig $arrayNodeConfig
  24. */
  25. public function __construct(ArrayNodeConfig $arrayNodeConfig)
  26. {
  27. $this->arrayNodeConfig = $arrayNodeConfig;
  28. }
  29. /**
  30. * Convert dom node tree to array in general case or to string in a case of a text node
  31. *
  32. * Example:
  33. * <node attr="val">
  34. * <subnode>val2<subnode>
  35. * </node>
  36. *
  37. * is converted to
  38. *
  39. * array(
  40. * 'node' => array(
  41. * 'attr' => 'wal',
  42. * 'subnode' => 'val2'
  43. * )
  44. * )
  45. *
  46. * @param \DOMNode $source
  47. * @param string $basePath
  48. * @return string|array
  49. * @throws \UnexpectedValueException
  50. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  51. */
  52. public function convert(\DOMNode $source, $basePath = '')
  53. {
  54. $value = [];
  55. /** @var \DOMNode $node */
  56. foreach ($source->childNodes as $node) {
  57. if ($node->nodeType == XML_ELEMENT_NODE) {
  58. $nodeName = $node->nodeName;
  59. $nodePath = $basePath . '/' . $nodeName;
  60. $arrayKeyAttribute = $this->arrayNodeConfig->getAssocArrayKeyAttribute($nodePath);
  61. $isNumericArrayNode = $this->arrayNodeConfig->isNumericArray($nodePath);
  62. $isArrayNode = $isNumericArrayNode || $arrayKeyAttribute;
  63. if (isset($value[$nodeName]) && !$isArrayNode) {
  64. throw new \UnexpectedValueException(
  65. "Node path '{$nodePath}' is not unique, but it has not been marked as array."
  66. );
  67. }
  68. $nodeData = $this->convert($node, $nodePath);
  69. if ($isArrayNode) {
  70. if ($isNumericArrayNode) {
  71. $value[$nodeName][] = $nodeData;
  72. } elseif (isset($nodeData[$arrayKeyAttribute])) {
  73. $arrayKeyValue = $nodeData[$arrayKeyAttribute];
  74. $value[$nodeName][$arrayKeyValue] = $nodeData;
  75. } else {
  76. throw new \UnexpectedValueException(
  77. "Array is expected to contain value for key '{$arrayKeyAttribute}'."
  78. );
  79. }
  80. } else {
  81. $value[$nodeName] = $nodeData;
  82. }
  83. } elseif ($node->nodeType == XML_CDATA_SECTION_NODE
  84. || ($node->nodeType == XML_TEXT_NODE && trim($node->nodeValue) != '')
  85. ) {
  86. $value = $node->nodeValue;
  87. break;
  88. }
  89. }
  90. $result = $this->getNodeAttributes($source);
  91. if (is_array($value)) {
  92. $result = array_merge($result, $value);
  93. if (!$result) {
  94. $result = '';
  95. }
  96. } else {
  97. if ($result) {
  98. $result['value'] = trim($value);
  99. } else {
  100. $result = trim($value);
  101. }
  102. }
  103. return $result;
  104. }
  105. /**
  106. * Retrieve key-value pairs of node attributes
  107. *
  108. * @param \DOMNode $node
  109. * @return array
  110. */
  111. protected function getNodeAttributes(\DOMNode $node)
  112. {
  113. $result = [];
  114. $attributes = $node->attributes ?: [];
  115. /** @var \DOMNode $attribute */
  116. foreach ($attributes as $attribute) {
  117. if ($attribute->nodeType == XML_ATTRIBUTE_NODE) {
  118. $result[$attribute->nodeName] = $attribute->nodeValue;
  119. }
  120. }
  121. return $result;
  122. }
  123. }