vendor/sulu/sulu/src/Sulu/Component/Content/Query/ContentQueryBuilder.php line 92

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\Component\Content\Query;
  11. use Sulu\Component\Content\Compat\PropertyInterface;
  12. use Sulu\Component\Content\Compat\Structure;
  13. use Sulu\Component\Content\Compat\StructureInterface;
  14. use Sulu\Component\Content\Compat\StructureManagerInterface;
  15. use Sulu\Component\Content\Extension\ExtensionManagerInterface;
  16. use Sulu\Component\Content\Mapper\Translation\MultipleTranslatedProperties;
  17. use Sulu\Component\Content\Mapper\Translation\TranslatedProperty;
  18. /**
  19. * Basic class for content query builder.
  20. */
  21. abstract class ContentQueryBuilder implements ContentQueryBuilderInterface
  22. {
  23. /**
  24. * @var StructureManagerInterface
  25. */
  26. protected $structureManager;
  27. /**
  28. * @var ExtensionManagerInterface
  29. */
  30. protected $extensionManager;
  31. /**
  32. * @var string
  33. */
  34. protected $languageNamespace;
  35. /**
  36. * @var MultipleTranslatedProperties
  37. */
  38. private $translatedProperties;
  39. /**
  40. * @var string[]
  41. */
  42. private $defaultProperties = [
  43. 'template',
  44. 'changed',
  45. 'changer',
  46. 'creator',
  47. 'created',
  48. 'nodeType',
  49. 'state',
  50. 'shadow-on',
  51. ];
  52. /**
  53. * @var string[]
  54. */
  55. protected $properties = [];
  56. /**
  57. * Only published content.
  58. *
  59. * @var bool
  60. */
  61. protected $published = true;
  62. /**
  63. * Load Excerpt data.
  64. *
  65. * @var bool
  66. */
  67. protected $excerpt = true;
  68. protected static $mixinTypes = ['sulu:page', 'sulu:home'];
  69. public function __construct(
  70. StructureManagerInterface $structureManager,
  71. ExtensionManagerInterface $extensionManager,
  72. $languageNamespace
  73. ) {
  74. $this->structureManager = $structureManager;
  75. $this->extensionManager = $extensionManager;
  76. $this->languageNamespace = $languageNamespace;
  77. $properties = \array_unique(\array_merge($this->defaultProperties, $this->properties));
  78. $this->translatedProperties = new MultipleTranslatedProperties($properties, $this->languageNamespace);
  79. }
  80. /**
  81. * Returns translated property name.
  82. */
  83. protected function getPropertyName($property)
  84. {
  85. return $this->translatedProperties->getName($property);
  86. }
  87. /**
  88. * Configures translated properties to given locale.
  89. *
  90. * @param string $locale
  91. */
  92. protected function setLocale($locale)
  93. {
  94. $this->translatedProperties->setLanguage($locale);
  95. }
  96. public function build($webspaceKey, $locales)
  97. {
  98. $additionalFields = [];
  99. $where = '';
  100. $select = ['page.*'];
  101. $order = [];
  102. foreach ($locales as $locale) {
  103. $this->setLocale($locale);
  104. $additionalFields[$locale] = [];
  105. if ($this->excerpt) {
  106. $this->buildSelectorForExcerpt($locale, $additionalFields);
  107. }
  108. $customSelect = $this->buildSelect($webspaceKey, $locale, $additionalFields);
  109. if ('' !== $customSelect) {
  110. $select[] = $customSelect;
  111. }
  112. if ($this->published) {
  113. $where .= \sprintf(
  114. '%s ((page.[%s] = %s OR page.[%s] = %s)',
  115. '' !== $where ? 'OR ' : '',
  116. $this->getPropertyName('state'),
  117. Structure::STATE_PUBLISHED,
  118. $this->getPropertyName('shadow-on'),
  119. 'true'
  120. );
  121. }
  122. $customWhere = $this->buildWhere($webspaceKey, $locale);
  123. if (null !== $customWhere && '' !== $customWhere) {
  124. $where = $where . ('' !== $where ? ' AND ' : '') . $customWhere;
  125. }
  126. if ($this->published) {
  127. $where .= ')';
  128. }
  129. $customOrder = $this->buildOrder($webspaceKey, $locale);
  130. if (!empty($customOrder)) {
  131. $order[] = $customOrder;
  132. } else {
  133. $order = ['[jcr:path] ASC'];
  134. }
  135. }
  136. $mixinTypeWhere = \implode(' OR ', \array_map(function($mixinType) {
  137. return 'page.[jcr:mixinTypes] = "' . $mixinType . '"';
  138. }, static::$mixinTypes));
  139. $sql2 = \sprintf(
  140. 'SELECT %s
  141. FROM [nt:unstructured] AS page
  142. WHERE (%s)
  143. AND (%s)
  144. %s %s',
  145. \implode(', ', $select),
  146. $mixinTypeWhere,
  147. $where,
  148. \count($order) > 0 ? 'ORDER BY' : '',
  149. \implode(', ', $order)
  150. );
  151. return [$sql2, $additionalFields];
  152. }
  153. public function getPublished()
  154. {
  155. return $this->published;
  156. }
  157. /**
  158. * Returns custom select statement.
  159. */
  160. abstract protected function buildWhere($webspaceKey, $locale);
  161. /**
  162. * Returns custom where statement.
  163. */
  164. abstract protected function buildSelect($webspaceKey, $locale, &$additionalFields);
  165. /**
  166. * Returns custom order statement.
  167. */
  168. protected function buildOrder($webspaceKey, $locale)
  169. {
  170. return '';
  171. }
  172. /**
  173. * Returns select statement with all url and title properties.
  174. */
  175. private function buildSelectForStructures($locale, $structures, &$names)
  176. {
  177. $result = '';
  178. // add node name and url to selector
  179. /** @var StructureInterface $structure */
  180. foreach ($structures as $structure) {
  181. $result .= $this->buildSelectForStructure($locale, $structure, $names);
  182. }
  183. return $result;
  184. }
  185. /**
  186. * Returns select of a single structure with title and url selector.
  187. */
  188. private function buildSelectForStructure($locale, StructureInterface $structure, &$names)
  189. {
  190. $nodeNameProperty = $structure->getProperty('title');
  191. $result = '';
  192. $name = $this->getTranslatedProperty($nodeNameProperty, $locale)->getName();
  193. if (!\in_array($name, $names)) {
  194. $names[] = $name;
  195. $result .= ', ' . $this->buildSelector($name);
  196. }
  197. if ($structure->hasTag('sulu.rlp')) {
  198. $urlProperty = $structure->getPropertyByTagName('sulu.rlp');
  199. $name = $this->getTranslatedProperty($urlProperty, $locale)->getName();
  200. if ('resource_locator' !== $urlProperty->getContentTypeName() && !\in_array($name, $names)) {
  201. $names[] = $name;
  202. $result .= ', ' . $this->buildSelector($name);
  203. }
  204. }
  205. return $result;
  206. }
  207. /**
  208. * Returns a select statement for excerpt data.
  209. */
  210. private function buildSelectorForExcerpt($locale, &$additionalFields)
  211. {
  212. $excerptStructure = $this->structureManager->getStructure('excerpt');
  213. $extension = $this->extensionManager->getExtension('', 'excerpt');
  214. foreach ($excerptStructure->getProperties(true) as $property) {
  215. $additionalFields[$locale][] = [
  216. 'extension' => $extension,
  217. 'target' => 'excerpt',
  218. 'property' => $property->getName(),
  219. 'name' => $property->getName(),
  220. ];
  221. }
  222. }
  223. /**
  224. * Returns single select statement.
  225. */
  226. protected function buildSelector($name)
  227. {
  228. return \sprintf('page.[%s]', $name);
  229. }
  230. /**
  231. * Returns a translated property.
  232. */
  233. protected function getTranslatedProperty(PropertyInterface $property, $locale)
  234. {
  235. return new TranslatedProperty($property, $locale, $this->languageNamespace);
  236. }
  237. }