DiRule.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. /**
  3. * Rule for searching php file dependency
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\TestFramework\Dependency;
  9. use DOMDocument;
  10. use DOMXPath;
  11. use Magento\Framework\App\Utility\Files;
  12. use Magento\TestFramework\Dependency\VirtualType\VirtualTypeMapper;
  13. class DiRule implements RuleInterface
  14. {
  15. /**
  16. * @var VirtualTypeMapper
  17. */
  18. private $mapper;
  19. /**
  20. * @var string
  21. */
  22. private $pattern;
  23. /**
  24. * @param VirtualTypeMapper $mapper
  25. */
  26. public function __construct(VirtualTypeMapper $mapper)
  27. {
  28. $this->mapper = $mapper;
  29. }
  30. /**
  31. * @return string
  32. * @throws \Exception
  33. */
  34. private function getPattern()
  35. {
  36. if ($this->pattern === null) {
  37. $this->pattern = '~\b(?<class>(?<module>('
  38. . implode('[_\\\\]|', Files::init()->getNamespaces())
  39. . '[_\\\\])[a-zA-Z0-9]+)[a-zA-Z0-9_\\\\]*)\b~';
  40. }
  41. return $this->pattern;
  42. }
  43. /**
  44. * @var array
  45. */
  46. private static $tagNameMap = [
  47. 'type' => ['name'],
  48. 'preference' => [
  49. 'type',
  50. 'for'
  51. ],
  52. 'plugin' => ['type'],
  53. 'virtualType' => ['type']
  54. ];
  55. /**
  56. * Gets alien dependencies information for current module by analyzing file's contents
  57. *
  58. * @param string $currentModule
  59. * @param string $fileType
  60. * @param string $file
  61. * @param string $contents
  62. * @return array
  63. * @throws \Exception
  64. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  65. */
  66. public function getDependencyInfo($currentModule, $fileType, $file, &$contents)
  67. {
  68. if (pathinfo($file, PATHINFO_BASENAME) !== 'di.xml') {
  69. return [];
  70. }
  71. $dependenciesInfo = [];
  72. $scope = $this->mapper->getScopeFromFile($file);
  73. foreach ($this->fetchPossibleDependencies($contents) as $type => $deps) {
  74. foreach ($deps as $dep) {
  75. $dep = $this->mapper->getType($dep, $scope);
  76. if (preg_match($this->getPattern(), $dep, $matches)) {
  77. $referenceModule = str_replace('_', '\\', $matches['module']);
  78. if ($currentModule === $referenceModule) {
  79. continue;
  80. }
  81. $dependenciesInfo[] = [
  82. 'module' => $referenceModule,
  83. 'type' => $type,
  84. 'source' => $matches['class'],
  85. ];
  86. }
  87. }
  88. }
  89. return $dependenciesInfo;
  90. }
  91. /**
  92. * @param string $contents
  93. * @return array
  94. */
  95. private function fetchPossibleDependencies($contents)
  96. {
  97. $doc = new DOMDocument();
  98. $doc->loadXML($contents);
  99. return [
  100. RuleInterface::TYPE_SOFT => $this->getSoftDependencies($doc),
  101. RuleInterface::TYPE_HARD => $this->getHardDependencies($doc)
  102. ];
  103. }
  104. /**
  105. * @param DOMDocument $doc
  106. * @return array
  107. */
  108. private function getSoftDependencies(DOMDocument $doc)
  109. {
  110. $result = [];
  111. foreach (self::$tagNameMap as $tagName => $attributeNames) {
  112. $nodes = $doc->getElementsByTagName($tagName);
  113. /** @var \DOMElement $node */
  114. foreach ($nodes as $node) {
  115. foreach ($attributeNames as $attributeName) {
  116. $result[] = $node->getAttribute($attributeName);
  117. }
  118. }
  119. }
  120. return $result;
  121. }
  122. /**
  123. * @param DOMDocument $doc
  124. * @return array
  125. */
  126. private function getHardDependencies(DOMDocument $doc)
  127. {
  128. $result = [];
  129. $xpath = new DOMXPath($doc);
  130. $textNodes = $xpath->query('//*[@xsi:type="object"]');
  131. /** @var \DOMElement $node */
  132. foreach ($textNodes as $node) {
  133. $result[] = $node->nodeValue;
  134. }
  135. return $result;
  136. }
  137. }