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

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