Converter.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Config\Model\Config\Structure;
  7. /**
  8. * @api
  9. * @since 100.0.2
  10. */
  11. class Converter implements \Magento\Framework\Config\ConverterInterface
  12. {
  13. /**
  14. * @var \Magento\Config\Model\Config\Structure\Mapper\Factory
  15. */
  16. protected $_mapperFactory;
  17. /**
  18. * Mapper type list
  19. *
  20. * @var string[]
  21. */
  22. protected $_mapperList = [
  23. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_EXTENDS,
  24. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_PATH,
  25. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_DEPENDENCIES,
  26. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_ATTRIBUTE_INHERITANCE,
  27. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_IGNORE,
  28. \Magento\Config\Model\Config\Structure\Mapper\Factory::MAPPER_SORTING,
  29. ];
  30. /**
  31. * Map of single=>plural sub-node names per node
  32. *
  33. * E.G. first element makes all 'tab' nodes be renamed to 'tabs' in system node.
  34. *
  35. * @var array
  36. */
  37. protected $_nameMap = [
  38. 'system' => ['tab' => 'tabs', 'section' => 'sections'],
  39. 'section' => ['group' => 'children'],
  40. 'group' => ['field' => 'children', 'group' => 'children'],
  41. 'depends' => ['field' => 'fields'],
  42. ];
  43. /**
  44. * @param \Magento\Config\Model\Config\Structure\Mapper\Factory $mapperFactory
  45. */
  46. public function __construct(\Magento\Config\Model\Config\Structure\Mapper\Factory $mapperFactory)
  47. {
  48. $this->_mapperFactory = $mapperFactory;
  49. }
  50. /**
  51. * Convert dom document
  52. *
  53. * @param \DOMNode $source
  54. * @return array
  55. */
  56. public function convert($source)
  57. {
  58. $result = $this->_convertDOMDocument($source);
  59. foreach ($this->_mapperList as $type) {
  60. /** @var $mapper MapperInterface */
  61. $mapper = $this->_mapperFactory->create($type);
  62. $result = $mapper->map($result);
  63. }
  64. return $result;
  65. }
  66. /**
  67. * Retrieve \DOMDocument as array
  68. *
  69. * @param \DOMNode $root
  70. * @return array|null
  71. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  72. * @SuppressWarnings(PHPMD.NPathComplexity)
  73. */
  74. protected function _convertDOMDocument(\DOMNode $root)
  75. {
  76. $result = $this->_processAttributes($root);
  77. $children = $root->childNodes;
  78. $processedSubLists = [];
  79. for ($i = 0; $i < $children->length; $i++) {
  80. $child = $children->item($i);
  81. $childName = $child->nodeName;
  82. $convertedChild = [];
  83. switch ($child->nodeType) {
  84. case XML_COMMENT_NODE:
  85. continue 2;
  86. break;
  87. case XML_TEXT_NODE:
  88. if ($children->length && trim($child->nodeValue, "\n ") === '') {
  89. continue 2;
  90. }
  91. $childName = 'value';
  92. $convertedChild = $child->nodeValue;
  93. break;
  94. case XML_CDATA_SECTION_NODE:
  95. $childName = 'value';
  96. $convertedChild = $child->nodeValue;
  97. break;
  98. default:
  99. /** @var $child \DOMElement */
  100. if ($childName == 'attribute') {
  101. $childName = $child->getAttribute('type');
  102. }
  103. $convertedChild = $this->_convertDOMDocument($child);
  104. break;
  105. }
  106. if (array_key_exists(
  107. $root->nodeName,
  108. $this->_nameMap
  109. ) && array_key_exists(
  110. $child->nodeName,
  111. $this->_nameMap[$root->nodeName]
  112. )
  113. ) {
  114. $childName = $this->_nameMap[$root->nodeName][$child->nodeName];
  115. $processedSubLists[] = $childName;
  116. $convertedChild['_elementType'] = $child->nodeName;
  117. }
  118. if (in_array($childName, $processedSubLists)) {
  119. $result = $this->_addProcessedNode($convertedChild, $result, $childName);
  120. } elseif (array_key_exists($childName, $result)) {
  121. $result[$childName] = [$result[$childName], $convertedChild];
  122. $processedSubLists[] = $childName;
  123. } else {
  124. $result[$childName] = $convertedChild;
  125. }
  126. }
  127. if (count($result) == 1 && array_key_exists('value', $result)) {
  128. $result = $result['value'];
  129. }
  130. if ($result == []) {
  131. $result = null;
  132. }
  133. return $result;
  134. }
  135. /**
  136. * Add converted child with processed name
  137. *
  138. * @param array $convertedChild
  139. * @param array $result
  140. * @param string $childName
  141. * @return array
  142. */
  143. protected function _addProcessedNode($convertedChild, $result, $childName)
  144. {
  145. if (is_array($convertedChild) && array_key_exists('id', $convertedChild)) {
  146. $result[$childName][$convertedChild['id']] = $convertedChild;
  147. } else {
  148. $result[$childName][] = $convertedChild;
  149. }
  150. return $result;
  151. }
  152. /**
  153. * Process element attributes
  154. *
  155. * @param \DOMNode $root
  156. * @return array
  157. */
  158. protected function _processAttributes(\DOMNode $root)
  159. {
  160. $result = [];
  161. if ($root->hasAttributes()) {
  162. $attributes = $root->attributes;
  163. foreach ($attributes as $attribute) {
  164. if ($root->nodeName == 'attribute' && $attribute->name == 'type') {
  165. continue;
  166. }
  167. $result[$attribute->name] = $attribute->value;
  168. }
  169. return $result;
  170. }
  171. return $result;
  172. }
  173. }