Converter.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. /**
  3. * Attributes configuration converter
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. declare(strict_types=1);
  9. namespace Magento\Framework\Setup\Declaration\Schema\Config;
  10. /**
  11. * This converter is required for Declaration Filesystem reader:
  12. *
  13. * @see \Magento\Framework\Setup\Declaration\Schema\FileSystem\XmlReader
  14. *
  15. * Allows to convert declarative schema to raw array and add default values
  16. * for column types and for constraints.
  17. */
  18. class Converter implements \Magento\Framework\Config\ConverterInterface
  19. {
  20. /**
  21. * Convert config from XML to array.
  22. *
  23. * @param \DOMDocument $source
  24. * @return array
  25. */
  26. public function convert($source): array
  27. {
  28. $output = $this->recursiveConvert($this->getTablesNode($source));
  29. return $output;
  30. }
  31. /**
  32. * We exactly know, that our schema is consists from tables.
  33. * So we do not need root elements in result, only table names.
  34. * So proposed to select only tables from all DOMDocument.
  35. *
  36. * @param \DOMDocument $element
  37. * @return \DOMNodeList
  38. */
  39. private function getTablesNode(\DOMDocument $element): \DOMNodeList
  40. {
  41. return $element->getElementsByTagName('table');
  42. }
  43. /**
  44. * Convert elements.
  45. *
  46. * @param \Traversable $source
  47. * @return array
  48. */
  49. private function recursiveConvert(\Traversable $source): array
  50. {
  51. $output = [];
  52. foreach ($source as $element) {
  53. if ($element instanceof \DOMElement) {
  54. $key = $this->getIdAttributeValue($element);
  55. if ($element->hasChildNodes()) {
  56. $output[$element->tagName][$key] =
  57. array_replace(
  58. $this->recursiveConvert($element->childNodes),
  59. $this->interpretAttributes($element)
  60. );
  61. } elseif ($this->hasAttributesExceptIdAttribute($element)) {
  62. $output[$element->tagName][$key] = $this->interpretAttributes($element);
  63. } else {
  64. $output[$element->tagName][$key] = $key;
  65. }
  66. }
  67. }
  68. return $output;
  69. }
  70. /**
  71. * Provide the value of the ID attribute for each element.
  72. *
  73. * @param \DOMElement $element
  74. * @return string
  75. */
  76. private function getIdAttributeValue(\DOMElement $element): string
  77. {
  78. $idAttributeValue = '';
  79. switch ($element->tagName) {
  80. case ('table'):
  81. case ('column'):
  82. $idAttributeValue = $element->getAttribute('name');
  83. break;
  84. case ('index'):
  85. case ('constraint'):
  86. $idAttributeValue = $element->getAttribute('referenceId');
  87. break;
  88. }
  89. return $idAttributeValue;
  90. }
  91. /**
  92. * Check whether we have any attributes except ID attribute.
  93. *
  94. * @param \DOMElement $element
  95. * @return bool
  96. */
  97. private function hasAttributesExceptIdAttribute(\DOMElement $element)
  98. {
  99. return $element->hasAttribute('xsi:type') || $element->attributes->length >= 2;
  100. }
  101. /**
  102. * Mix attributes that comes from XML schema with default ones.
  103. *
  104. * So if you will not have some attribute in schema - it will be taken from default one.
  105. *
  106. * @param \DOMElement $domElement
  107. * @return array
  108. */
  109. private function interpretAttributes(\DOMElement $domElement): array
  110. {
  111. $attributes = $this->getAttributes($domElement);
  112. $xsiType = $domElement->getAttribute('xsi:type');
  113. if ($xsiType) {
  114. $attributes['type'] = $xsiType;
  115. }
  116. return $attributes;
  117. }
  118. /**
  119. * Convert XML attributes into raw array with attributes.
  120. *
  121. * @param \DOMElement $element
  122. * @return array
  123. */
  124. private function getAttributes(\DOMElement $element): array
  125. {
  126. $attributes = [];
  127. $attributeNodes = $element->attributes;
  128. /** @var \DOMAttr $attribute */
  129. foreach ($attributeNodes as $domAttr) {
  130. $attributes[$domAttr->name] = $domAttr->value;
  131. }
  132. return $attributes;
  133. }
  134. }