Config.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\ObjectManager\Config;
  7. use Magento\Framework\Serialize\SerializerInterface;
  8. use Magento\Framework\ObjectManager\ConfigCacheInterface;
  9. use Magento\Framework\ObjectManager\DefinitionInterface;
  10. use Magento\Framework\ObjectManager\RelationsInterface;
  11. class Config implements \Magento\Framework\ObjectManager\ConfigInterface
  12. {
  13. /**
  14. * Config cache
  15. *
  16. * @var ConfigCacheInterface
  17. */
  18. protected $_cache;
  19. /**
  20. * Class definitions
  21. *
  22. * @var \Magento\Framework\ObjectManager\DefinitionInterface
  23. */
  24. protected $_definitions;
  25. /**
  26. * Current cache key
  27. *
  28. * @var string
  29. */
  30. protected $_currentCacheKey;
  31. /**
  32. * Interface preferences
  33. *
  34. * @var array
  35. */
  36. protected $_preferences = [];
  37. /**
  38. * Virtual types
  39. *
  40. * @var array
  41. */
  42. protected $_virtualTypes = [];
  43. /**
  44. * Instance arguments
  45. *
  46. * @var array
  47. */
  48. protected $_arguments = [];
  49. /**
  50. * Type shareability
  51. *
  52. * @var array
  53. */
  54. protected $_nonShared = [];
  55. /**
  56. * List of relations
  57. *
  58. * @var RelationsInterface
  59. */
  60. protected $_relations;
  61. /**
  62. * List of merged arguments
  63. *
  64. * @var array
  65. */
  66. protected $_mergedArguments;
  67. /**
  68. * @var \Magento\Framework\Serialize\SerializerInterface
  69. */
  70. private $serializer;
  71. /**
  72. * @param RelationsInterface $relations
  73. * @param DefinitionInterface $definitions
  74. */
  75. public function __construct(RelationsInterface $relations = null, DefinitionInterface $definitions = null)
  76. {
  77. $this->_relations = $relations ?: new \Magento\Framework\ObjectManager\Relations\Runtime();
  78. $this->_definitions = $definitions ?: new \Magento\Framework\ObjectManager\Definition\Runtime();
  79. }
  80. /**
  81. * Set class relations
  82. *
  83. * @param RelationsInterface $relations
  84. * @return void
  85. */
  86. public function setRelations(RelationsInterface $relations)
  87. {
  88. $this->_relations = $relations;
  89. }
  90. /**
  91. * Set cache instance
  92. *
  93. * @param ConfigCacheInterface $cache
  94. * @return void
  95. */
  96. public function setCache(ConfigCacheInterface $cache)
  97. {
  98. $this->_cache = $cache;
  99. }
  100. /**
  101. * Retrieve list of arguments per type
  102. *
  103. * @param string $type
  104. * @return array
  105. */
  106. public function getArguments($type)
  107. {
  108. if (isset($this->_mergedArguments[$type])) {
  109. return $this->_mergedArguments[$type];
  110. }
  111. return $this->_collectConfiguration($type);
  112. }
  113. /**
  114. * Check whether type is shared
  115. *
  116. * @param string $type
  117. * @return bool
  118. */
  119. public function isShared($type)
  120. {
  121. return !isset($this->_nonShared[$type]);
  122. }
  123. /**
  124. * Retrieve instance type
  125. *
  126. * @param string $instanceName
  127. * @return mixed
  128. */
  129. public function getInstanceType($instanceName)
  130. {
  131. while (isset($this->_virtualTypes[$instanceName])) {
  132. $instanceName = $this->_virtualTypes[$instanceName];
  133. }
  134. return $instanceName;
  135. }
  136. /**
  137. * Retrieve preference for type
  138. *
  139. * @param string $type
  140. * @return string
  141. * @throws \LogicException
  142. */
  143. public function getPreference($type)
  144. {
  145. $type = ltrim($type, '\\');
  146. $preferencePath = [];
  147. while (isset($this->_preferences[$type])) {
  148. if (isset($preferencePath[$this->_preferences[$type]])) {
  149. throw new \LogicException(
  150. 'Circular type preference: ' .
  151. $type .
  152. ' relates to ' .
  153. $this->_preferences[$type] .
  154. ' and viceversa.'
  155. );
  156. }
  157. $type = $this->_preferences[$type];
  158. $preferencePath[$type] = 1;
  159. }
  160. return $type;
  161. }
  162. /**
  163. * Collect parent types configuration for requested type
  164. *
  165. * @param string $type
  166. * @return array
  167. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  168. */
  169. protected function _collectConfiguration($type)
  170. {
  171. if (!isset($this->_mergedArguments[$type])) {
  172. if (isset($this->_virtualTypes[$type])) {
  173. $arguments = $this->_collectConfiguration($this->_virtualTypes[$type]);
  174. } elseif ($this->_relations->has($type)) {
  175. $relations = $this->_relations->getParents($type);
  176. $arguments = [];
  177. foreach ($relations as $relation) {
  178. if ($relation) {
  179. $relationArguments = $this->_collectConfiguration($relation);
  180. if ($relationArguments) {
  181. $arguments = array_replace($arguments, $relationArguments);
  182. }
  183. }
  184. }
  185. } else {
  186. $arguments = [];
  187. }
  188. if (isset($this->_arguments[$type])) {
  189. if ($arguments && count($arguments)) {
  190. $arguments = array_replace_recursive($arguments, $this->_arguments[$type]);
  191. } else {
  192. $arguments = $this->_arguments[$type];
  193. }
  194. }
  195. $this->_mergedArguments[$type] = $arguments;
  196. return $arguments;
  197. }
  198. return $this->_mergedArguments[$type];
  199. }
  200. /**
  201. * Merge configuration
  202. *
  203. * @param array $configuration
  204. * @return void
  205. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  206. */
  207. protected function _mergeConfiguration(array $configuration)
  208. {
  209. foreach ($configuration as $key => $curConfig) {
  210. switch ($key) {
  211. case 'preferences':
  212. foreach ($curConfig as $for => $to) {
  213. $this->_preferences[ltrim($for, '\\')] = ltrim($to, '\\');
  214. }
  215. break;
  216. default:
  217. $key = ltrim($key, '\\');
  218. if (isset($curConfig['type'])) {
  219. $this->_virtualTypes[$key] = ltrim($curConfig['type'], '\\');
  220. }
  221. if (isset($curConfig['arguments'])) {
  222. if (!empty($this->_mergedArguments)) {
  223. $this->_mergedArguments = [];
  224. }
  225. if (isset($this->_arguments[$key])) {
  226. $this->_arguments[$key] = array_replace($this->_arguments[$key], $curConfig['arguments']);
  227. } else {
  228. $this->_arguments[$key] = $curConfig['arguments'];
  229. }
  230. }
  231. if (isset($curConfig['shared'])) {
  232. if (!$curConfig['shared']) {
  233. $this->_nonShared[$key] = 1;
  234. } else {
  235. unset($this->_nonShared[$key]);
  236. }
  237. }
  238. break;
  239. }
  240. }
  241. }
  242. /**
  243. * Extend configuration
  244. *
  245. * @param array $configuration
  246. * @return void
  247. */
  248. public function extend(array $configuration)
  249. {
  250. if ($this->_cache) {
  251. if (!$this->_currentCacheKey) {
  252. $this->_currentCacheKey = md5(
  253. $this->getSerializer()->serialize(
  254. [$this->_arguments, $this->_nonShared, $this->_preferences, $this->_virtualTypes]
  255. )
  256. );
  257. }
  258. $key = md5($this->_currentCacheKey . $this->getSerializer()->serialize($configuration));
  259. $cached = $this->_cache->get($key);
  260. if ($cached) {
  261. list(
  262. $this->_arguments,
  263. $this->_nonShared,
  264. $this->_preferences,
  265. $this->_virtualTypes,
  266. $this->_mergedArguments
  267. ) = $cached;
  268. } else {
  269. $this->_mergeConfiguration($configuration);
  270. if (!$this->_mergedArguments) {
  271. foreach ($this->_definitions->getClasses() as $class) {
  272. $this->_collectConfiguration($class);
  273. }
  274. }
  275. $this->_cache->save(
  276. [
  277. $this->_arguments,
  278. $this->_nonShared,
  279. $this->_preferences,
  280. $this->_virtualTypes,
  281. $this->_mergedArguments,
  282. ],
  283. $key
  284. );
  285. }
  286. $this->_currentCacheKey = $key;
  287. } else {
  288. $this->_mergeConfiguration($configuration);
  289. }
  290. }
  291. /**
  292. * Returns list of virtual types
  293. *
  294. * @return array
  295. */
  296. public function getVirtualTypes()
  297. {
  298. return $this->_virtualTypes;
  299. }
  300. /**
  301. * Returns list on preferences
  302. *
  303. * @return array
  304. */
  305. public function getPreferences()
  306. {
  307. return $this->_preferences;
  308. }
  309. /**
  310. * Get serializer
  311. *
  312. * @return \Magento\Framework\Serialize\SerializerInterface
  313. * @deprecated 101.0.0
  314. */
  315. private function getSerializer()
  316. {
  317. if ($this->serializer === null) {
  318. $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()
  319. ->get(SerializerInterface::class);
  320. }
  321. return $this->serializer;
  322. }
  323. }