TMap.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\ObjectManager;
  7. use Magento\Framework\ObjectManagerInterface;
  8. /**
  9. * Class TMap
  10. * @internal
  11. */
  12. class TMap implements \IteratorAggregate, \Countable, \ArrayAccess
  13. {
  14. /**
  15. * @var string
  16. */
  17. private $type;
  18. /**
  19. * @var array
  20. */
  21. private $array = [];
  22. /**
  23. * @var array
  24. */
  25. private $objectsArray = [];
  26. /**
  27. * @var int
  28. */
  29. private $counter = 0;
  30. /**
  31. * @var ObjectManagerInterface
  32. */
  33. private $objectManager;
  34. /**
  35. * @var ConfigInterface
  36. */
  37. private $configInterface;
  38. /**
  39. * @var \Closure
  40. */
  41. private $objectCreationStrategy;
  42. /**
  43. * @param string $type
  44. * @param ObjectManagerInterface $objectManager
  45. * @param ConfigInterface $configInterface
  46. * @param array $array
  47. * @param \Closure $objectCreationStrategy
  48. */
  49. public function __construct(
  50. $type,
  51. ObjectManagerInterface $objectManager,
  52. ConfigInterface $configInterface,
  53. array $array = [],
  54. \Closure $objectCreationStrategy = null
  55. ) {
  56. if (!class_exists($this->type) && !interface_exists($type)) {
  57. throw new \InvalidArgumentException(sprintf('Unknown type %s', $type));
  58. }
  59. $this->type = $type;
  60. $this->objectManager = $objectManager;
  61. $this->configInterface = $configInterface;
  62. array_walk(
  63. $array,
  64. function ($item, $index) {
  65. $this->assertValidTypeLazy($item, $index);
  66. }
  67. );
  68. $this->array = $array;
  69. $this->counter = count($array);
  70. $this->objectCreationStrategy = $objectCreationStrategy;
  71. }
  72. /**
  73. * Asserts that item type is collection defined type
  74. *
  75. * @param string $instanceName
  76. * @param string|int|null $index
  77. * @return void
  78. * @throws \InvalidArgumentException
  79. */
  80. private function assertValidTypeLazy($instanceName, $index = null)
  81. {
  82. $realType = $this->configInterface->getInstanceType(
  83. $this->configInterface->getPreference($instanceName)
  84. );
  85. if (!in_array(
  86. $this->type,
  87. array_unique(array_merge(class_parents($realType), class_implements($realType))),
  88. true
  89. )) {
  90. $this->throwTypeException($realType, $index);
  91. }
  92. }
  93. /**
  94. * Throws exception according type mismatch
  95. *
  96. * @param string $inputType
  97. * @param string $index
  98. * @return void
  99. * @throws \InvalidArgumentException
  100. */
  101. private function throwTypeException($inputType, $index)
  102. {
  103. $message = 'Type mismatch. Expected type: %s. Actual: %s, Code: %s';
  104. throw new \InvalidArgumentException(
  105. sprintf($message, $this->type, $inputType, $index)
  106. );
  107. }
  108. /**
  109. * Returns object for requested index
  110. *
  111. * @param string|int $index
  112. * @return object
  113. */
  114. private function initObject($index)
  115. {
  116. if (isset($this->objectsArray[$index])) {
  117. return $this->objectsArray[$index];
  118. }
  119. $objectCreationStrategy = $this->objectCreationStrategy;
  120. return $this->objectsArray[$index] = $objectCreationStrategy === null
  121. ? $this->objectManager->create($this->array[$index])
  122. : $objectCreationStrategy($this->objectManager, $this->array[$index]);
  123. }
  124. /**
  125. * {inheritdoc}
  126. */
  127. public function getIterator()
  128. {
  129. if (array_keys($this->array) != array_keys($this->objectsArray)) {
  130. foreach (array_keys($this->array) as $index) {
  131. $this->initObject($index);
  132. }
  133. }
  134. return new \ArrayIterator($this->objectsArray);
  135. }
  136. /**
  137. * {inheritdoc}
  138. */
  139. public function offsetExists($offset)
  140. {
  141. return array_key_exists($offset, $this->array);
  142. }
  143. /**
  144. * {inheritdoc}
  145. */
  146. public function offsetGet($offset)
  147. {
  148. return isset($this->array[$offset]) ? $this->initObject($offset) : null;
  149. }
  150. /**
  151. * {inheritdoc}
  152. */
  153. public function offsetSet($offset, $value)
  154. {
  155. $this->assertValidTypeLazy($value, $offset);
  156. if ($offset === null) {
  157. $this->array[] = $value;
  158. } else {
  159. $this->array[$offset] = $value;
  160. }
  161. $this->counter++;
  162. }
  163. /**
  164. * {inheritdoc}
  165. */
  166. public function offsetUnset($offset)
  167. {
  168. if ($this->counter && isset($this->array[$offset])) {
  169. $this->counter--;
  170. unset($this->array[$offset]);
  171. if (isset($this->objectsArray[$offset])) {
  172. unset($this->objectsArray[$offset]);
  173. }
  174. }
  175. }
  176. /**
  177. * {inheritdoc}
  178. */
  179. public function count()
  180. {
  181. return $this->counter;
  182. }
  183. }