vendor/sulu/sulu/src/Sulu/Bundle/WebsiteBundle/Navigation/NavigationMapper.php line 130

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Sulu.
  4. *
  5. * (c) Sulu GmbH
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Sulu\Bundle\WebsiteBundle\Navigation;
  11. use Sulu\Component\Content\Compat\Structure;
  12. use Sulu\Component\Content\Compat\StructureInterface;
  13. use Sulu\Component\Content\Mapper\ContentMapperInterface;
  14. use Sulu\Component\Content\Query\ContentQueryBuilderInterface;
  15. use Sulu\Component\Content\Query\ContentQueryExecutorInterface;
  16. use Sulu\Component\PHPCR\SessionManager\SessionManagerInterface;
  17. use Sulu\Component\Security\Authorization\PermissionTypes;
  18. use Symfony\Component\Stopwatch\Stopwatch;
  19. class NavigationMapper implements NavigationMapperInterface
  20. {
  21. /**
  22. * @var ContentMapperInterface
  23. */
  24. private $contentMapper;
  25. /**
  26. * @var ContentQueryExecutorInterface
  27. */
  28. private $contentQueryExecutor;
  29. /**
  30. * @var ContentQueryBuilderInterface
  31. */
  32. private $queryBuilder;
  33. /**
  34. * @var SessionManagerInterface
  35. */
  36. private $sessionManager;
  37. /**
  38. * @var Stopwatch
  39. */
  40. private $stopwatch;
  41. /**
  42. * @var array
  43. */
  44. private $permissions;
  45. /**
  46. * @var array
  47. */
  48. private $enabledTwigAttributes = [];
  49. public function __construct(
  50. ContentMapperInterface $contentMapper,
  51. ContentQueryExecutorInterface $contentQueryExecutor,
  52. ContentQueryBuilderInterface $queryBuilder,
  53. SessionManagerInterface $sessionManager,
  54. ?Stopwatch $stopwatch = null,
  55. $permissions = null,
  56. array $enabledTwigAttributes = [
  57. 'path' => true,
  58. ]
  59. ) {
  60. $this->contentMapper = $contentMapper;
  61. $this->contentQueryExecutor = $contentQueryExecutor;
  62. $this->queryBuilder = $queryBuilder;
  63. $this->sessionManager = $sessionManager;
  64. $this->stopwatch = $stopwatch;
  65. $this->permissions = $permissions;
  66. $this->enabledTwigAttributes = $enabledTwigAttributes;
  67. if ($enabledTwigAttributes['path'] ?? true) {
  68. @trigger_deprecation('sulu/sulu', '2.3', 'Enabling the "path" parameter is deprecated.');
  69. }
  70. }
  71. public function getNavigation(
  72. $parent,
  73. $webspaceKey,
  74. $locale,
  75. $depth = 1,
  76. $flat = false,
  77. $context = null,
  78. $loadExcerpt = false,
  79. $segmentKey = null
  80. ) {
  81. if ($this->stopwatch) {
  82. $this->stopwatch->start('NavigationMapper::getNavigation');
  83. }
  84. $rootDepth = \substr_count($this->sessionManager->getContentNode($webspaceKey)->getPath(), '/');
  85. $parent = $this->sessionManager->getSession()->getNodeByIdentifier($parent)->getPath();
  86. $depth = $depth + \substr_count($parent, '/') - $rootDepth;
  87. $this->queryBuilder->init(
  88. [
  89. 'context' => $context,
  90. 'parent' => $parent,
  91. 'excerpt' => $loadExcerpt,
  92. 'segmentKey' => $segmentKey,
  93. ]
  94. );
  95. $result = $this->contentQueryExecutor->execute(
  96. $webspaceKey,
  97. [$locale],
  98. $this->queryBuilder,
  99. $flat,
  100. $depth,
  101. null,
  102. null,
  103. false,
  104. $this->permissions[PermissionTypes::VIEW] ?? null
  105. );
  106. $result = $this->normalizeResult($result);
  107. if ($this->stopwatch) {
  108. $this->stopwatch->stop('NavigationMapper::getNavigation');
  109. }
  110. return $result;
  111. }
  112. public function getRootNavigation(
  113. $webspaceKey,
  114. $locale,
  115. $depth = 1,
  116. $flat = false,
  117. $context = null,
  118. $loadExcerpt = false,
  119. $segmentKey = null
  120. ) {
  121. if ($this->stopwatch) {
  122. $this->stopwatch->start('NavigationMapper::getRootNavigation.query');
  123. }
  124. $this->queryBuilder->init(['context' => $context, 'excerpt' => $loadExcerpt, 'segmentKey' => $segmentKey]);
  125. $result = $this->contentQueryExecutor->execute(
  126. $webspaceKey,
  127. [$locale],
  128. $this->queryBuilder,
  129. $flat,
  130. $depth,
  131. null,
  132. null,
  133. false,
  134. $this->permissions[PermissionTypes::VIEW] ?? null
  135. );
  136. $result = $this->normalizeResult($result);
  137. if ($this->stopwatch) {
  138. $this->stopwatch->stop('NavigationMapper::getRootNavigation.query');
  139. }
  140. return $result;
  141. }
  142. public function getBreadcrumb($uuid, $webspace, $language)
  143. {
  144. $breadcrumbItems = $this->contentMapper->loadBreadcrumb($uuid, $language, $webspace);
  145. $result = [];
  146. foreach ($breadcrumbItems as $item) {
  147. $result[] = $this->contentMapper->load($item->getUuid(), $webspace, $language);
  148. }
  149. $result[] = $this->contentMapper->load($uuid, $webspace, $language);
  150. return $this->generateNavigation($result, $webspace, $language, false, null, true, false);
  151. }
  152. /**
  153. * generate navigation items for given contents.
  154. */
  155. private function generateNavigation(
  156. $contents,
  157. $webspace,
  158. $language,
  159. $flat = false,
  160. $context = null,
  161. $breakOnNotInNavigation = false,
  162. $recursive = true
  163. ) {
  164. $result = [];
  165. /** @var StructureInterface $content */
  166. foreach ($contents as $content) {
  167. if ($this->inNavigation($content, $context)) {
  168. $url = $content->getResourceLocator();
  169. $title = $content->getTitle();
  170. $children = $recursive ? $this->generateChildNavigation($content, $webspace, $language, $flat, $context) : [];
  171. if (false === $flat) {
  172. $result[] = new NavigationItem(
  173. $title,
  174. $url,
  175. isset($content->getExt()['excerpt']) ? $content->getExt()['excerpt'] : null,
  176. $children,
  177. $content->getUuid(),
  178. $content->getNodeType()
  179. );
  180. } else {
  181. $result[] = new NavigationItem(
  182. $title,
  183. $url,
  184. isset($content->getExt()['excerpt']) ? $content->getExt()['excerpt'] : null,
  185. null,
  186. $content->getUuid(),
  187. $content->getNodeType()
  188. );
  189. $result = \array_merge($result, $children);
  190. }
  191. } elseif (true === $flat) {
  192. $children = $recursive ? $this->generateChildNavigation($content, $webspace, $language, $flat, $context) : [];
  193. $result = \array_merge($result, $children);
  194. } elseif ($breakOnNotInNavigation) {
  195. break;
  196. }
  197. }
  198. return $result;
  199. }
  200. /**
  201. * generate child navigation of given content.
  202. */
  203. private function generateChildNavigation(
  204. StructureInterface $content,
  205. $webspace,
  206. $language,
  207. $flat = false,
  208. $context = null
  209. ) {
  210. $children = [];
  211. if (\is_array($content->getChildren()) && \count($content->getChildren()) > 0) {
  212. $children = $this->generateNavigation(
  213. $content->getChildren(),
  214. $webspace,
  215. $language,
  216. $flat,
  217. $context
  218. );
  219. }
  220. return $children;
  221. }
  222. /**
  223. * checks if content should be displayed.
  224. *
  225. * @param string|null $context
  226. *
  227. * @return bool
  228. */
  229. public function inNavigation(StructureInterface $content, $context = null)
  230. {
  231. $contexts = $content->getNavContexts();
  232. if (Structure::STATE_PUBLISHED !== $content->getNodeState()) {
  233. // if node state is not published do not show page
  234. return false;
  235. }
  236. if (\is_array($contexts) && (null === $context || \in_array($context, $contexts))) {
  237. // all contexts or content has context
  238. return true;
  239. }
  240. // do not show
  241. return false;
  242. }
  243. private function normalizeResult(array $result)
  244. {
  245. foreach ($result as $key => $item) {
  246. if (isset($item['children'])) {
  247. $item['children'] = $this->normalizeResult($item['children']);
  248. } else {
  249. $item['children'] = [];
  250. }
  251. if (!($this->enabledTwigAttributes['path'] ?? true)) {
  252. unset($item['path']);
  253. }
  254. $result[$key] = $item;
  255. }
  256. return $result;
  257. }
  258. }