AbstractFactory.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\ObjectManager\Factory;
  7. use Magento\Framework\Exception\RuntimeException;
  8. use Magento\Framework\ObjectManagerInterface;
  9. use Magento\Framework\Phrase;
  10. use Psr\Log\LoggerInterface;
  11. use Magento\Framework\App\ObjectManager;
  12. abstract class AbstractFactory implements \Magento\Framework\ObjectManager\FactoryInterface
  13. {
  14. /**
  15. * Object manager
  16. *
  17. * @var ObjectManagerInterface
  18. */
  19. protected $objectManager;
  20. /**
  21. * Object manager config
  22. *
  23. * @var \Magento\Framework\ObjectManager\ConfigInterface
  24. */
  25. protected $config;
  26. /**
  27. * Definition list
  28. *
  29. * @var \Magento\Framework\ObjectManager\DefinitionInterface
  30. */
  31. protected $definitions;
  32. /**
  33. * Global arguments
  34. *
  35. * @var array
  36. */
  37. protected $globalArguments;
  38. /**
  39. * Object creation stack
  40. *
  41. * @var array
  42. */
  43. protected $creationStack = [];
  44. /**
  45. * @param \Magento\Framework\ObjectManager\ConfigInterface $config
  46. * @param ObjectManagerInterface $objectManager
  47. * @param \Magento\Framework\ObjectManager\DefinitionInterface $definitions
  48. * @param array $globalArguments
  49. */
  50. public function __construct(
  51. \Magento\Framework\ObjectManager\ConfigInterface $config,
  52. ObjectManagerInterface $objectManager = null,
  53. \Magento\Framework\ObjectManager\DefinitionInterface $definitions = null,
  54. $globalArguments = []
  55. ) {
  56. $this->config = $config;
  57. $this->objectManager = $objectManager;
  58. $this->definitions = $definitions ?: $this->getDefinitions();
  59. $this->globalArguments = $globalArguments;
  60. }
  61. /**
  62. * Set object manager
  63. *
  64. * @param ObjectManagerInterface $objectManager
  65. *
  66. * @return void
  67. */
  68. public function setObjectManager(ObjectManagerInterface $objectManager)
  69. {
  70. $this->objectManager = $objectManager;
  71. }
  72. /**
  73. * Set global arguments
  74. *
  75. * @param array $arguments
  76. *
  77. * @return void
  78. */
  79. public function setArguments($arguments)
  80. {
  81. $this->globalArguments = $arguments;
  82. }
  83. /**
  84. * @return \Magento\Framework\ObjectManager\DefinitionInterface
  85. */
  86. public function getDefinitions()
  87. {
  88. if ($this->definitions === null) {
  89. $this->definitions = new \Magento\Framework\ObjectManager\Definition\Runtime();
  90. }
  91. return $this->definitions;
  92. }
  93. /**
  94. * Create object
  95. *
  96. * @param string $type
  97. * @param array $args
  98. *
  99. * @return object
  100. * @throws RuntimeException
  101. */
  102. protected function createObject($type, $args)
  103. {
  104. try {
  105. return new $type(...array_values($args));
  106. } catch (\TypeError $exception) {
  107. /** @var LoggerInterface $logger */
  108. $logger = ObjectManager::getInstance()->get(LoggerInterface::class);
  109. $logger->critical(
  110. sprintf('Type Error occurred when creating object: %s, %s', $type, $exception->getMessage())
  111. );
  112. throw new RuntimeException(
  113. new Phrase('Type Error occurred when creating object: %type', ['type' => $type])
  114. );
  115. }
  116. }
  117. /**
  118. * Resolve an argument
  119. *
  120. * @param array &$argument
  121. * @param string $paramType
  122. * @param mixed $paramDefault
  123. * @param string $paramName
  124. * @param string $requestedType
  125. *
  126. * @return void
  127. *
  128. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  129. */
  130. protected function resolveArgument(&$argument, $paramType, $paramDefault, $paramName, $requestedType)
  131. {
  132. if ($paramType && $argument !== $paramDefault && !is_object($argument)) {
  133. if (!isset($argument['instance']) || $argument !== (array)$argument) {
  134. throw new \UnexpectedValueException(
  135. 'Invalid parameter configuration provided for $' . $paramName . ' argument of ' . $requestedType
  136. );
  137. }
  138. $argumentType = $argument['instance'];
  139. if (isset($argument['shared'])) {
  140. $isShared = $argument['shared'];
  141. } else {
  142. $isShared = $this->config->isShared($argumentType);
  143. }
  144. if ($isShared) {
  145. $argument = $this->objectManager->get($argumentType);
  146. } else {
  147. $argument = $this->objectManager->create($argumentType);
  148. }
  149. } elseif ($argument === (array)$argument) {
  150. if (isset($argument['argument'])) {
  151. if (isset($this->globalArguments[$argument['argument']])) {
  152. $argument = $this->globalArguments[$argument['argument']];
  153. } else {
  154. $argument = $paramDefault;
  155. }
  156. } elseif (!empty($argument)) {
  157. $this->parseArray($argument);
  158. }
  159. }
  160. }
  161. /**
  162. * Parse array argument
  163. *
  164. * @param array $array
  165. *
  166. * @return void
  167. */
  168. protected function parseArray(&$array)
  169. {
  170. foreach ($array as $key => $item) {
  171. if ($item === (array)$item) {
  172. if (isset($item['instance'])) {
  173. if (isset($item['shared'])) {
  174. $isShared = $item['shared'];
  175. } else {
  176. $isShared = $this->config->isShared($item['instance']);
  177. }
  178. if ($isShared) {
  179. $array[$key] = $this->objectManager->get($item['instance']);
  180. } else {
  181. $array[$key] = $this->objectManager->create($item['instance']);
  182. }
  183. } elseif (isset($item['argument'])) {
  184. if (isset($this->globalArguments[$item['argument']])) {
  185. $array[$key] = $this->globalArguments[$item['argument']];
  186. } else {
  187. $array[$key] = null;
  188. }
  189. } else {
  190. $this->parseArray($array[$key]);
  191. }
  192. }
  193. }
  194. }
  195. /**
  196. * Resolve constructor arguments
  197. *
  198. * @param string $requestedType
  199. * @param array $parameters
  200. * @param array $arguments
  201. *
  202. * @return array
  203. *
  204. * @throws \UnexpectedValueException
  205. * @throws \BadMethodCallException
  206. */
  207. protected function resolveArgumentsInRuntime($requestedType, array $parameters, array $arguments = [])
  208. {
  209. $resolvedArguments = [];
  210. foreach ($parameters as $parameter) {
  211. list($paramName, $paramType, $paramRequired, $paramDefault) = $parameter;
  212. $argument = null;
  213. if (!empty($arguments) && (isset($arguments[$paramName]) || array_key_exists($paramName, $arguments))) {
  214. $argument = $arguments[$paramName];
  215. } elseif ($paramRequired) {
  216. if ($paramType) {
  217. $argument = ['instance' => $paramType];
  218. } else {
  219. $this->creationStack = [];
  220. throw new \BadMethodCallException(
  221. 'Missing required argument $' . $paramName . ' of ' . $requestedType . '.'
  222. );
  223. }
  224. } else {
  225. $argument = $paramDefault;
  226. }
  227. $this->resolveArgument($argument, $paramType, $paramDefault, $paramName, $requestedType);
  228. $resolvedArguments[] = $argument;
  229. }
  230. return $resolvedArguments;
  231. }
  232. }