GeneratorPool.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\View\Layout;
  7. use Magento\Framework\View\Layout\Condition\ConditionFactory;
  8. /**
  9. * Pool of generators for structural elements
  10. * @api
  11. * @since 100.0.2
  12. */
  13. class GeneratorPool
  14. {
  15. /**
  16. * @var ScheduledStructure\Helper
  17. */
  18. protected $helper;
  19. /**
  20. * @var GeneratorInterface[]
  21. */
  22. protected $generators = [];
  23. /**
  24. * @var \Psr\Log\LoggerInterface
  25. */
  26. protected $logger;
  27. /**
  28. * @var \Magento\Framework\View\Layout\Condition\ConditionFactory
  29. */
  30. private $conditionFactory;
  31. /**
  32. * @param ScheduledStructure\Helper $helper
  33. * @param ConditionFactory $conditionFactory
  34. * @param \Psr\Log\LoggerInterface $logger
  35. * @param array $generators
  36. */
  37. public function __construct(
  38. ScheduledStructure\Helper $helper,
  39. ConditionFactory $conditionFactory,
  40. \Psr\Log\LoggerInterface $logger,
  41. array $generators = null
  42. ) {
  43. $this->helper = $helper;
  44. $this->conditionFactory = $conditionFactory;
  45. $this->logger = $logger;
  46. $this->addGenerators($generators);
  47. }
  48. /**
  49. * Get generator
  50. *
  51. * @param string $type
  52. * @return GeneratorInterface
  53. * @throws \InvalidArgumentException
  54. */
  55. public function getGenerator($type)
  56. {
  57. if (!isset($this->generators[$type])) {
  58. throw new \InvalidArgumentException("Invalid generator type '{$type}'");
  59. }
  60. return $this->generators[$type];
  61. }
  62. /**
  63. * Traverse through all generators and generate all scheduled elements
  64. *
  65. * @param Reader\Context $readerContext
  66. * @param Generator\Context $generatorContext
  67. * @return $this
  68. */
  69. public function process(Reader\Context $readerContext, Generator\Context $generatorContext)
  70. {
  71. $this->buildStructure($readerContext->getScheduledStructure(), $generatorContext->getStructure());
  72. foreach ($this->generators as $generator) {
  73. $generator->process($readerContext, $generatorContext);
  74. }
  75. return $this;
  76. }
  77. /**
  78. * Add generators to pool
  79. *
  80. * @param GeneratorInterface[] $generators
  81. * @return void
  82. */
  83. protected function addGenerators(array $generators)
  84. {
  85. foreach ($generators as $generator) {
  86. $this->generators[$generator->getType()] = $generator;
  87. }
  88. }
  89. /**
  90. * Build structure that is based on scheduled structure
  91. *
  92. * @param ScheduledStructure $scheduledStructure
  93. * @param Data\Structure $structure
  94. * @return $this
  95. */
  96. protected function buildStructure(ScheduledStructure $scheduledStructure, Data\Structure $structure)
  97. {
  98. //Schedule all element into nested structure
  99. while (false === $scheduledStructure->isStructureEmpty()) {
  100. $this->helper->scheduleElement($scheduledStructure, $structure, key($scheduledStructure->getStructure()));
  101. }
  102. $scheduledStructure->flushPaths();
  103. while (false === $scheduledStructure->isListToSortEmpty()) {
  104. $this->reorderElements($scheduledStructure, $structure, key($scheduledStructure->getListToSort()));
  105. }
  106. foreach ($scheduledStructure->getListToMove() as $elementToMove) {
  107. $this->moveElementInStructure($scheduledStructure, $structure, $elementToMove);
  108. }
  109. foreach ($scheduledStructure->getListToRemove() as $elementToRemove) {
  110. $this->removeElement($scheduledStructure, $structure, $elementToRemove);
  111. }
  112. foreach ($scheduledStructure->getElements() as $name => $data) {
  113. list(, $data) = $data;
  114. if ($this->visibilityConditionsExistsIn($data)) {
  115. $condition = $this->conditionFactory->create($data['attributes']['visibilityConditions']);
  116. if (!$condition->isVisible($data['attributes']['visibilityConditions'])) {
  117. $this->removeElement($scheduledStructure, $structure, $name);
  118. }
  119. }
  120. }
  121. return $this;
  122. }
  123. /**
  124. * Reorder a child of a specified element
  125. *
  126. * @param ScheduledStructure $scheduledStructure,
  127. * @param Data\Structure $structure
  128. * @param string $elementName
  129. * @return void
  130. */
  131. protected function reorderElements(
  132. ScheduledStructure $scheduledStructure,
  133. Data\Structure $structure,
  134. $elementName
  135. ) {
  136. $element = $scheduledStructure->getElementToSort($elementName);
  137. $scheduledStructure->unsetElementToSort($element[ScheduledStructure::ELEMENT_NAME]);
  138. if (isset($element[ScheduledStructure::ELEMENT_OFFSET_OR_SIBLING])) {
  139. $siblingElement = $scheduledStructure->getElementToSort(
  140. $element[ScheduledStructure::ELEMENT_OFFSET_OR_SIBLING]
  141. );
  142. if (isset($siblingElement[ScheduledStructure::ELEMENT_NAME])
  143. && $structure->hasElement($siblingElement[ScheduledStructure::ELEMENT_NAME])
  144. ) {
  145. $this->reorderElements(
  146. $scheduledStructure,
  147. $structure,
  148. $siblingElement[ScheduledStructure::ELEMENT_NAME]
  149. );
  150. }
  151. }
  152. $structure->reorderChildElement(
  153. $element[ScheduledStructure::ELEMENT_PARENT_NAME],
  154. $element[ScheduledStructure::ELEMENT_NAME],
  155. $element[ScheduledStructure::ELEMENT_OFFSET_OR_SIBLING],
  156. $element[ScheduledStructure::ELEMENT_IS_AFTER]
  157. );
  158. }
  159. /**
  160. * Remove scheduled element
  161. *
  162. * @param ScheduledStructure $scheduledStructure
  163. * @param Data\Structure $structure
  164. * @param string $elementName
  165. * @param bool $isChild
  166. * @return $this
  167. */
  168. protected function removeElement(
  169. ScheduledStructure $scheduledStructure,
  170. Data\Structure $structure,
  171. $elementName,
  172. $isChild = false
  173. ) {
  174. $elementsToRemove = array_keys($structure->getChildren($elementName));
  175. $scheduledStructure->unsetElement($elementName);
  176. foreach ($elementsToRemove as $element) {
  177. $this->removeElement($scheduledStructure, $structure, $element, true);
  178. }
  179. if (!$isChild) {
  180. $structure->unsetElement($elementName);
  181. $scheduledStructure->unsetElementFromListToRemove($elementName);
  182. }
  183. return $this;
  184. }
  185. /**
  186. * Move element in scheduled structure
  187. *
  188. * @param ScheduledStructure $scheduledStructure
  189. * @param Data\Structure $structure
  190. * @param string $element
  191. * @return $this
  192. */
  193. protected function moveElementInStructure(
  194. ScheduledStructure $scheduledStructure,
  195. Data\Structure $structure,
  196. $element
  197. ) {
  198. list($destination, $siblingName, $isAfter, $alias) = $scheduledStructure->getElementToMove($element);
  199. $childAlias = $structure->getChildAlias($structure->getParentId($element), $element);
  200. if (!$alias && false === $structure->getChildId($destination, $childAlias)) {
  201. $alias = $childAlias;
  202. }
  203. $structure->unsetChild($element, $alias);
  204. try {
  205. $structure->setAsChild($element, $destination, $alias);
  206. $structure->reorderChildElement($destination, $element, $siblingName, $isAfter);
  207. } catch (\OutOfBoundsException $e) {
  208. $this->logger->warning('Broken reference: ' . $e->getMessage());
  209. }
  210. $scheduledStructure->unsetElementFromBrokenParentList($element);
  211. return $this;
  212. }
  213. /**
  214. * @param array $data
  215. *
  216. * @return bool
  217. * @since 101.0.0
  218. */
  219. protected function visibilityConditionsExistsIn(array $data)
  220. {
  221. return isset($data['attributes']) &&
  222. array_key_exists('visibilityConditions', $data['attributes']) &&
  223. !empty($data['attributes']['visibilityConditions']);
  224. }
  225. }