Manager.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Ui\Model;
  7. use ArrayObject;
  8. use Magento\Framework\Data\Argument\InterpreterInterface;
  9. use Magento\Framework\Exception\LocalizedException;
  10. use Magento\Framework\Config\CacheInterface;
  11. use Magento\Framework\View\Element\UiComponent\ArrayObjectFactory;
  12. use Magento\Framework\View\Element\UiComponent\Config\Converter;
  13. use Magento\Framework\View\Element\UiComponent\Config\DomMergerInterface;
  14. use Magento\Framework\View\Element\UiComponent\Config\FileCollector\AggregatedFileCollectorFactory;
  15. use Magento\Framework\View\Element\UiComponent\Config\ManagerInterface;
  16. use Magento\Framework\View\Element\UiComponent\Config\Provider\Component\Definition as ComponentDefinition;
  17. use Magento\Framework\View\Element\UiComponent\Config\ReaderFactory;
  18. use Magento\Framework\View\Element\UiComponent\Config\UiReaderInterface;
  19. use Magento\Framework\Serialize\SerializerInterface;
  20. use Magento\Framework\App\ObjectManager;
  21. /**
  22. * Class Manager
  23. * @deprecated 101.0.0
  24. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  25. */
  26. class Manager implements ManagerInterface
  27. {
  28. /**
  29. * ID in the storage cache
  30. */
  31. const CACHE_ID = 'ui_component_configuration_data';
  32. /**
  33. * Configuration provider for UI component
  34. *
  35. * @var ComponentDefinition
  36. */
  37. protected $componentConfigProvider;
  38. /**
  39. * Argument interpreter
  40. *
  41. * @var InterpreterInterface
  42. */
  43. protected $argumentInterpreter;
  44. /**
  45. * DOM document merger
  46. *
  47. * @var DomMergerInterface
  48. */
  49. protected $domMerger;
  50. /**
  51. * Factory for UI config reader
  52. *
  53. * @var ReaderFactory
  54. */
  55. protected $readerFactory;
  56. /**
  57. * Component data
  58. *
  59. * @var ArrayObject
  60. */
  61. protected $componentsData;
  62. /**
  63. * Components pool
  64. *
  65. * @var ArrayObject
  66. */
  67. protected $componentsPool;
  68. /**
  69. * Factory for ArrayObject
  70. *
  71. * @var ArrayObjectFactory
  72. */
  73. protected $arrayObjectFactory;
  74. /**
  75. * @var AggregatedFileCollectorFactory
  76. */
  77. protected $aggregatedFileCollectorFactory;
  78. /**
  79. * @var CacheInterface
  80. */
  81. protected $cache;
  82. /**
  83. * @var UiReaderInterface[]
  84. */
  85. protected $uiReader;
  86. /**
  87. * @var SerializerInterface
  88. */
  89. private $serializer;
  90. /**
  91. * @param ComponentDefinition $componentConfigProvider
  92. * @param DomMergerInterface $domMerger
  93. * @param ReaderFactory $readerFactory
  94. * @param ArrayObjectFactory $arrayObjectFactory
  95. * @param AggregatedFileCollectorFactory $aggregatedFileCollectorFactory
  96. * @param CacheInterface $cache
  97. * @param InterpreterInterface $argumentInterpreter
  98. * @param SerializerInterface|null $serializer
  99. */
  100. public function __construct(
  101. ComponentDefinition $componentConfigProvider,
  102. DomMergerInterface $domMerger,
  103. ReaderFactory $readerFactory,
  104. ArrayObjectFactory $arrayObjectFactory,
  105. AggregatedFileCollectorFactory $aggregatedFileCollectorFactory,
  106. CacheInterface $cache,
  107. InterpreterInterface $argumentInterpreter,
  108. SerializerInterface $serializer = null
  109. ) {
  110. $this->componentConfigProvider = $componentConfigProvider;
  111. $this->domMerger = $domMerger;
  112. $this->readerFactory = $readerFactory;
  113. $this->arrayObjectFactory = $arrayObjectFactory;
  114. $this->componentsData = $this->arrayObjectFactory->create();
  115. $this->aggregatedFileCollectorFactory = $aggregatedFileCollectorFactory;
  116. $this->cache = $cache;
  117. $this->argumentInterpreter = $argumentInterpreter;
  118. $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
  119. }
  120. /**
  121. * Get component data
  122. *
  123. * @param string $name
  124. * @return array
  125. */
  126. public function getData($name)
  127. {
  128. return (array) $this->componentsData->offsetGet($name);
  129. }
  130. /**
  131. * Has component data
  132. *
  133. * @param string $name
  134. * @return bool
  135. */
  136. protected function hasData($name)
  137. {
  138. return $this->componentsData->offsetExists($name);
  139. }
  140. /**
  141. * Prepare the initialization data of UI components
  142. *
  143. * @param string $name
  144. * @return ManagerInterface
  145. * @throws \Magento\Framework\Exception\LocalizedException
  146. */
  147. public function prepareData($name)
  148. {
  149. if ($name === null || $this->hasData($name)) {
  150. throw new LocalizedException(
  151. new \Magento\Framework\Phrase(
  152. 'The "%1" UI component element name is invalid. Verify the name and try again.',
  153. [$name]
  154. )
  155. );
  156. }
  157. $this->componentsPool = $this->arrayObjectFactory->create();
  158. $cacheID = static::CACHE_ID . '_' . $name;
  159. $cachedPool = $this->cache->load($cacheID);
  160. if ($cachedPool === false) {
  161. $this->prepare($name);
  162. $this->cache->save(
  163. $this->serializer->serialize($this->componentsPool->getArrayCopy()),
  164. $cacheID
  165. );
  166. } else {
  167. $this->componentsPool->exchangeArray(
  168. $this->serializer->unserialize($cachedPool)
  169. );
  170. }
  171. $this->componentsData->offsetSet($name, $this->componentsPool);
  172. $this->componentsData->offsetSet($name, $this->evaluateComponentArguments($this->getData($name)));
  173. return $this;
  174. }
  175. /**
  176. * Evaluated components data
  177. *
  178. * @param array $components
  179. * @return array
  180. */
  181. protected function evaluateComponentArguments($components)
  182. {
  183. foreach ($components as &$component) {
  184. foreach ($component[ManagerInterface::COMPONENT_ARGUMENTS_KEY] as $argumentName => $argument) {
  185. $component[ManagerInterface::COMPONENT_ARGUMENTS_KEY][$argumentName]
  186. = $this->argumentInterpreter->evaluate($argument);
  187. }
  188. $component[ManagerInterface::CHILDREN_KEY] = $this->evaluateComponentArguments(
  189. $component[ManagerInterface::CHILDREN_KEY]
  190. );
  191. }
  192. return $components;
  193. }
  194. /**
  195. * To create the raw data components
  196. *
  197. * @param string $component
  198. * @param bool $evaluated
  199. * @return array
  200. */
  201. public function createRawComponentData($component, $evaluated = true)
  202. {
  203. $componentData = $this->componentConfigProvider->getComponentData($component);
  204. $componentData[Converter::DATA_ATTRIBUTES_KEY] = isset($componentData[Converter::DATA_ATTRIBUTES_KEY])
  205. ? $componentData[Converter::DATA_ATTRIBUTES_KEY]
  206. : [];
  207. $componentData[Converter::DATA_ARGUMENTS_KEY] = isset($componentData[Converter::DATA_ARGUMENTS_KEY])
  208. ? $componentData[Converter::DATA_ARGUMENTS_KEY]
  209. : [];
  210. if ($evaluated) {
  211. foreach ($componentData[Converter::DATA_ARGUMENTS_KEY] as $argumentName => $argument) {
  212. $componentData[Converter::DATA_ARGUMENTS_KEY][$argumentName]
  213. = $this->argumentInterpreter->evaluate($argument);
  214. }
  215. }
  216. return [
  217. ManagerInterface::COMPONENT_ATTRIBUTES_KEY => $componentData[Converter::DATA_ATTRIBUTES_KEY],
  218. ManagerInterface::COMPONENT_ARGUMENTS_KEY => $componentData[Converter::DATA_ARGUMENTS_KEY],
  219. ];
  220. }
  221. /**
  222. * Get UIReader and collect base files configuration
  223. *
  224. * @param string $name
  225. * @return UiReaderInterface
  226. */
  227. public function getReader($name)
  228. {
  229. if (!isset($this->uiReader[$name])) {
  230. $this->domMerger->unsetDom();
  231. $this->uiReader[$name] = $this->readerFactory->create(
  232. [
  233. 'fileCollector' => $this->aggregatedFileCollectorFactory->create(
  234. ['searchPattern' => sprintf(ManagerInterface::SEARCH_PATTERN, $name)]
  235. ),
  236. 'domMerger' => $this->domMerger
  237. ]
  238. );
  239. }
  240. return $this->uiReader[$name];
  241. }
  242. /**
  243. * Initialize the new component data
  244. *
  245. * @param string $name
  246. * @return void
  247. */
  248. protected function prepare($name)
  249. {
  250. $componentData = $this->getReader($name)->read();
  251. $componentsPool = reset($componentData);
  252. $componentsPool = reset($componentsPool);
  253. $componentsPool[Converter::DATA_ATTRIBUTES_KEY] = array_merge(
  254. ['name' => $name],
  255. $componentsPool[Converter::DATA_ATTRIBUTES_KEY]
  256. );
  257. $components = $this->createDataForComponent(key($componentData), [$componentsPool]);
  258. $this->addComponentIntoPool($name, reset($components));
  259. }
  260. /**
  261. * Create data for component instance
  262. *
  263. * @param string $name
  264. * @param array $componentsPool
  265. * @return array
  266. */
  267. protected function createDataForComponent($name, array $componentsPool)
  268. {
  269. $createdComponents = [];
  270. $rootComponent = $this->createRawComponentData($name, false);
  271. foreach ($componentsPool as $key => $component) {
  272. $resultConfiguration = [ManagerInterface::CHILDREN_KEY => []];
  273. $instanceName = $this->createName($component, $key, $name);
  274. $resultConfiguration[ManagerInterface::COMPONENT_ARGUMENTS_KEY] = $this->mergeArguments(
  275. $component,
  276. $rootComponent
  277. );
  278. unset($component[Converter::DATA_ARGUMENTS_KEY]);
  279. $resultConfiguration[ManagerInterface::COMPONENT_ATTRIBUTES_KEY] = $this->mergeAttributes(
  280. $component,
  281. $rootComponent
  282. );
  283. unset($component[Converter::DATA_ATTRIBUTES_KEY]);
  284. // Create inner components
  285. foreach ($component as $subComponentName => $subComponent) {
  286. if (is_array($subComponent)) {
  287. $resultConfiguration[ManagerInterface::CHILDREN_KEY] = array_merge(
  288. $resultConfiguration[ManagerInterface::CHILDREN_KEY],
  289. $this->createDataForComponent($subComponentName, $subComponent)
  290. );
  291. }
  292. }
  293. $createdComponents[$instanceName] = $resultConfiguration;
  294. }
  295. return $createdComponents;
  296. }
  297. /**
  298. * Add a component into pool
  299. *
  300. * @param string $instanceName
  301. * @param array $configuration
  302. * @return void
  303. */
  304. protected function addComponentIntoPool($instanceName, array $configuration)
  305. {
  306. $this->componentsPool->offsetSet($instanceName, $configuration);
  307. }
  308. /**
  309. * Merge component arguments
  310. *
  311. * @param array $componentData
  312. * @param array $rootComponentData
  313. * @return array
  314. */
  315. protected function mergeArguments(array $componentData, array $rootComponentData)
  316. {
  317. $baseArguments = isset($rootComponentData[ManagerInterface::COMPONENT_ARGUMENTS_KEY])
  318. ? $rootComponentData[ManagerInterface::COMPONENT_ARGUMENTS_KEY]
  319. : [];
  320. $componentArguments = isset($componentData[Converter::DATA_ARGUMENTS_KEY])
  321. ? $componentData[Converter::DATA_ARGUMENTS_KEY]
  322. : [];
  323. return array_replace_recursive($baseArguments, $componentArguments);
  324. }
  325. /**
  326. * Merge component attributes
  327. *
  328. * @param array $componentData
  329. * @param array $rootComponentData
  330. * @return array
  331. */
  332. protected function mergeAttributes(array $componentData, array $rootComponentData)
  333. {
  334. $baseAttributes = isset($rootComponentData[ManagerInterface::COMPONENT_ATTRIBUTES_KEY])
  335. ? $rootComponentData[ManagerInterface::COMPONENT_ATTRIBUTES_KEY]
  336. : [];
  337. $componentAttributes = isset($componentData[Converter::DATA_ATTRIBUTES_KEY])
  338. ? $componentData[Converter::DATA_ATTRIBUTES_KEY]
  339. : [];
  340. unset($componentAttributes['noNamespaceSchemaLocation']);
  341. return array_replace_recursive($baseAttributes, $componentAttributes);
  342. }
  343. /**
  344. * Create name component instance
  345. *
  346. * @param array $componentData
  347. * @param string|int $key
  348. * @param string $componentName
  349. * @return string
  350. */
  351. protected function createName(array $componentData, $key, $componentName)
  352. {
  353. return isset($componentData[Converter::DATA_ATTRIBUTES_KEY][Converter::NAME_ATTRIBUTE_KEY])
  354. ? $componentData[Converter::DATA_ATTRIBUTES_KEY][Converter::NAME_ATTRIBUTE_KEY]
  355. : sprintf(ManagerInterface::ANONYMOUS_TEMPLATE, $componentName, $key);
  356. }
  357. }