Dom.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. /**
  3. * This file is part of the Klarna Core module
  4. *
  5. * (c) Klarna Bank AB (publ)
  6. *
  7. * For the full copyright and license information, please view the NOTICE
  8. * and LICENSE files that were distributed with this source code.
  9. */
  10. namespace Klarna\Core\Config\Converter;
  11. use Magento\Framework\Config\ConverterInterface;
  12. /**
  13. * Converter class to manipulate XML into Array
  14. *
  15. * @package Klarna\Core\Config\Converter
  16. */
  17. class Dom implements ConverterInterface
  18. {
  19. /**
  20. * Convert config
  21. *
  22. * @param \DOMDocument $source
  23. * @return array
  24. */
  25. public function convert($source)
  26. {
  27. $klarnaNode = $this->getRootNode($source);
  28. $externalPaymentMethods = $this->getChildrenByName($klarnaNode, 'external_payment_method');
  29. $orderLines = $this->getChildrenByName($klarnaNode, 'order_lines');
  30. $paymentsOrderLines = $this->getChildrenByName($klarnaNode, 'payments_order_lines');
  31. return [
  32. 'external_payment_methods' => $this->collectExternalPaymentMethods($externalPaymentMethods),
  33. 'api_types' => $this->collectChildren($klarnaNode, 'api_type'),
  34. 'api_versions' => $this->collectChildren($klarnaNode, 'api_version'),
  35. 'merchant_checkbox' => $this->collectChildren($klarnaNode, 'merchant_checkbox'),
  36. 'order_lines' => $this->collectOrderLines($orderLines),
  37. 'payments_api_types' => $this->collectChildren($klarnaNode, 'payments_api_type'),
  38. 'payments_api_versions' => $this->collectChildren($klarnaNode, 'payments_api_version'),
  39. 'payments_order_lines' => $this->collectOrderLines($paymentsOrderLines),
  40. ];
  41. }
  42. /**
  43. * Get root node from XML
  44. *
  45. * @param \DOMDocument $document
  46. * @return \DOMElement
  47. */
  48. private function getRootNode(\DOMDocument $document)
  49. {
  50. $root = $this->getAllChildElements($document);
  51. return array_shift($root);
  52. }
  53. /**
  54. * Get all child elements from a node
  55. *
  56. * @param \DOMNode $source
  57. * @return \DOMElement[]
  58. */
  59. private function getAllChildElements(\DOMNode $source)
  60. {
  61. return array_filter(
  62. iterator_to_array($source->childNodes),
  63. function (\DOMNode $childNode) {
  64. return $childNode->nodeType === \XML_ELEMENT_NODE;
  65. }
  66. );
  67. }
  68. /**
  69. * Get all child elements from a named parent node
  70. *
  71. * @param \DOMElement $parent
  72. * @param string $name
  73. * @param bool $asArray
  74. * @return array|\DOMElement
  75. */
  76. private function getChildrenByName(\DOMElement $parent, $name, $asArray = true)
  77. {
  78. $element = array_filter(
  79. $this->getAllChildElements($parent),
  80. function (\DOMElement $child) use ($name) {
  81. return $child->nodeName === $name;
  82. }
  83. );
  84. if (!is_array($element)) {
  85. $element = [$element];
  86. }
  87. if ($asArray) {
  88. return $element;
  89. }
  90. return array_shift($element);
  91. }
  92. /**
  93. * Process external_payment_methods tree
  94. *
  95. * @param array $rootNode
  96. * @return array
  97. */
  98. private function collectExternalPaymentMethods(array $rootNode)
  99. {
  100. $result = [];
  101. foreach ($rootNode as $methodNode) {
  102. $method = $this->getAttribute($methodNode, 'id');
  103. $data = $this->collectAllChildValues($methodNode);
  104. if (array_key_exists($method, $result)) {
  105. $data = array_merge($result[$method], $data);
  106. }
  107. $result[$method] = $data;
  108. }
  109. return $result;
  110. }
  111. /**
  112. * Get an attribute from a node by attribute name
  113. *
  114. * @param \DOMElement $element
  115. * @param string $name
  116. * @return string
  117. */
  118. private function getAttribute(\DOMElement $element, $name)
  119. {
  120. return $element->attributes->getNamedItem($name)->nodeValue;
  121. }
  122. /**
  123. * Iterate through tree from parent node building an
  124. * array of all elements and their values
  125. *
  126. * @param \DOMElement $parent
  127. * @return array
  128. */
  129. private function collectAllChildValues(\DOMElement $parent)
  130. {
  131. $childNodes = $this->getAllChildElements($parent);
  132. $data = [];
  133. foreach ($childNodes as $node) {
  134. $data[$node->nodeName] = [];
  135. foreach ($this->getChildrenByName($parent, $node->nodeName) as $childNode) {
  136. $result = $this->collectAllChildValues($childNode);
  137. $key = $node->nodeName;
  138. if ($node->hasAttribute('id')) {
  139. $key = $node->getAttribute('id');
  140. unset($data[$node->nodeName]);
  141. }
  142. $value = $node->nodeValue;
  143. if (!is_array($result)) {
  144. $result = $value;
  145. }
  146. if (is_array($result) && empty($result)) {
  147. $result = $value;
  148. }
  149. $data[$key] = $result;
  150. }
  151. }
  152. return $data;
  153. }
  154. /**
  155. * Process a tree from a node
  156. *
  157. * @param \DOMElement $rootNode
  158. * @param $childName
  159. * @param string $idField
  160. * @return array
  161. */
  162. private function collectChildren(\DOMElement $rootNode, $childName, $idField = 'id')
  163. {
  164. $result = [];
  165. foreach ($this->getChildrenByName($rootNode, $childName) as $methodNode) {
  166. $method = $this->getAttribute($methodNode, $idField);
  167. $data = $this->collectAllChildValues($methodNode);
  168. if (array_key_exists($method, $result)) {
  169. $data = array_merge($result[$method], $data);
  170. }
  171. $result[$method] = $data;
  172. }
  173. return $result;
  174. }
  175. /**
  176. * @param array $rootNode
  177. * @return array
  178. */
  179. private function collectOrderLines(array $rootNode)
  180. {
  181. $result = [];
  182. foreach ($rootNode as $lineNode) {
  183. $line = $this->getAttribute($lineNode, 'id');
  184. $lines = $this->getAllChildElements($lineNode);
  185. $data = $this->processLines($lines);
  186. if (array_key_exists($line, $result)) {
  187. $data = array_merge($result[$line], $data);
  188. }
  189. $result[$line] = $data;
  190. }
  191. return $result;
  192. }
  193. /**
  194. * @param \DOMElement[] $lines
  195. * @return array
  196. */
  197. private function processLines(array $lines)
  198. {
  199. $result = [];
  200. foreach ($lines as $line) {
  201. $result[$line->getAttribute('id')] = [
  202. 'class' => $line->getAttribute('class')
  203. ];
  204. }
  205. return $result;
  206. }
  207. }