DumpConfigSourceAggregated.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Config\App\Config\Source;
  7. use Magento\Config\Model\Config\Export\ExcludeList;
  8. use Magento\Config\Model\Config\TypePool;
  9. use Magento\Framework\App\Config\ConfigSourceInterface;
  10. use Magento\Framework\App\Config\ScopeConfigInterface;
  11. use Magento\Framework\App\ObjectManager;
  12. /**
  13. * Class DumpConfigSourceAggregated aggregates configurations from all available sources
  14. */
  15. class DumpConfigSourceAggregated implements DumpConfigSourceInterface
  16. {
  17. /**
  18. * Rule name for include configuration data.
  19. */
  20. const RULE_TYPE_INCLUDE = 'include';
  21. /**
  22. * Rule name for exclude configuration data.
  23. */
  24. const RULE_TYPE_EXCLUDE = 'exclude';
  25. /**
  26. * Checker for config type.
  27. *
  28. * @var TypePool
  29. */
  30. private $typePool;
  31. /**
  32. * @var ConfigSourceInterface[]
  33. */
  34. private $sources;
  35. /**
  36. * @var array
  37. */
  38. private $excludedFields;
  39. /**
  40. * @var array
  41. */
  42. private $data;
  43. /**
  44. * Array of rules for filtration the configuration data.
  45. *
  46. * For example:
  47. * ```php
  48. * [
  49. * 'default' => 'include',
  50. * 'sensitive' => 'exclude',
  51. * 'environment' => 'exclude',
  52. * ]
  53. * ```
  54. * It means that all aggregated configuration data will be included in result but configurations
  55. * that relates to 'sensitive' or 'environment' will be excluded.
  56. *
  57. *
  58. * ```php
  59. * [
  60. * 'default' => 'exclude',
  61. * 'sensitive' => 'include',
  62. * 'environment' => 'include',
  63. * ]
  64. * ```
  65. * It means that result will contains only 'sensitive' and 'environment' configurations.
  66. *
  67. * @var array
  68. */
  69. private $rules;
  70. /**
  71. * @param ExcludeList $excludeList Is not used anymore as it was deprecated, use TypePool instead.
  72. * @param array $sources
  73. * @param TypePool|null $typePool
  74. * @param array $rules Rules for filtration the configuration data.
  75. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  76. */
  77. public function __construct(
  78. ExcludeList $excludeList,
  79. array $sources = [],
  80. TypePool $typePool = null,
  81. array $rules = []
  82. ) {
  83. $this->sources = $sources;
  84. $this->typePool = $typePool ?: ObjectManager::getInstance()->get(TypePool::class);
  85. $this->rules = $rules;
  86. }
  87. /**
  88. * Retrieve aggregated configuration from all available sources.
  89. *
  90. * @param string $path
  91. * @return array
  92. */
  93. public function get($path = '')
  94. {
  95. $path = (string)$path;
  96. $data = [];
  97. if (isset($this->data[$path])) {
  98. return $this->data[$path];
  99. }
  100. $this->sortSources();
  101. foreach ($this->sources as $sourceConfig) {
  102. /** @var ConfigSourceInterface $source */
  103. $source = $sourceConfig['source'];
  104. $data = array_replace_recursive($data, $source->get($path));
  105. }
  106. $this->excludedFields = [];
  107. $this->filterChain($path, $data);
  108. return $this->data[$path] = $data;
  109. }
  110. /**
  111. * Recursive filtering of sensitive data
  112. *
  113. * @param string $path
  114. * @param array $data
  115. * @return void
  116. */
  117. private function filterChain($path, &$data)
  118. {
  119. foreach ($data as $subKey => &$subData) {
  120. $newPath = $path ? $path . '/' . $subKey : $subKey;
  121. $filteredPath = $this->filterPath($newPath);
  122. if (is_array($subData)) {
  123. $this->filterChain($newPath, $subData);
  124. } elseif ($this->isExcludedPath($filteredPath)) {
  125. $this->excludedFields[$newPath] = $filteredPath;
  126. unset($data[$subKey]);
  127. }
  128. if (empty($subData) && isset($data[$subKey]) && is_array($data[$subKey])) {
  129. unset($data[$subKey]);
  130. }
  131. }
  132. }
  133. /**
  134. * Checks if the configuration field needs to be excluded.
  135. *
  136. * @param string $path Configuration field path. For example 'contact/email/recipient_email'
  137. * @return boolean Return true if path should be excluded
  138. */
  139. private function isExcludedPath($path)
  140. {
  141. if (empty($path)) {
  142. return false;
  143. }
  144. $defaultRule = isset($this->rules['default']) ?
  145. $this->rules['default'] : self::RULE_TYPE_INCLUDE;
  146. foreach ($this->rules as $type => $rule) {
  147. if ($type === 'default') {
  148. continue;
  149. }
  150. if ($this->typePool->isPresent($path, $type)) {
  151. return $rule === self::RULE_TYPE_EXCLUDE;
  152. }
  153. }
  154. return $defaultRule === self::RULE_TYPE_EXCLUDE;
  155. }
  156. /**
  157. * Eliminating scope info from path
  158. *
  159. * @param string $path
  160. * @return null|string
  161. */
  162. private function filterPath($path)
  163. {
  164. $parts = explode('/', $path);
  165. // Check if there are enough parts to recognize scope
  166. if (count($parts) < 3) {
  167. return null;
  168. }
  169. if ($parts[0] === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
  170. unset($parts[0]);
  171. } else {
  172. unset($parts[0], $parts[1]);
  173. }
  174. return implode('/', $parts);
  175. }
  176. /**
  177. * Sort sources ASC from higher priority to lower
  178. *
  179. * @return void
  180. */
  181. private function sortSources()
  182. {
  183. uasort($this->sources, function ($firstItem, $secondItem) {
  184. return $firstItem['sortOrder'] > $secondItem['sortOrder'];
  185. });
  186. }
  187. /**
  188. * Retrieves list of field paths were excluded from config dump
  189. * @return array
  190. */
  191. public function getExcludedFields()
  192. {
  193. $this->get();
  194. $fields = array_values($this->excludedFields);
  195. $fields = array_unique($fields);
  196. return $fields;
  197. }
  198. }