‪TYPO3CMS  ‪main
SuggestWizardDefaultReceiver.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
27 use TYPO3\CMS\Core\Imaging\IconSize;
32 
40 {
46  protected ‪$table = '';
47 
54  protected ‪$mmForeignTable = '';
55 
61  protected ‪$config = [];
62 
68  protected ‪$allowedPages = [];
69 
75  protected ‪$maxItems = 10;
76 
80  protected ‪$params = [];
81 
85  protected ‪$iconFactory;
86 
90  protected ‪$queryBuilder;
91 
98  public function ‪__construct(‪$table, ‪$config)
99  {
100  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
101  $this->queryBuilder = $this->‪getQueryBuilderForTable(‪$table);
102  $this->queryBuilder->getRestrictions()
103  ->removeAll()
104  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
105  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace));
106  $this->table = ‪$table;
107  $this->config = ‪$config;
108  // get a list of all the pages that should be looked on
109  if (isset(‪$config['pidList'])) {
110  $pageIds = ‪GeneralUtility::intExplode(',', (string)‪$config['pidList'], true);
111  $depth = (int)(‪$config['pidDepth'] ?? 0);
112  $availablePageIds = $this->‪getAvailablePageIds($pageIds, $depth);
113  $this->allowedPages = array_unique(array_merge($this->allowedPages, $availablePageIds));
114  }
115  if (isset(‪$config['maxItemsInResultList'])) {
116  $this->maxItems = ‪$config['maxItemsInResultList'];
117  }
118  $backendUser = $this->‪getBackendUser();
119  $backendUser->initializeWebmountsForElementBrowser();
120  if ($this->table === 'pages') {
121  $this->queryBuilder->andWhere(
122  ‪QueryHelper::stripLogicalOperatorPrefix($backendUser->getPagePermsClause(‪Permission::PAGE_SHOW)),
123  $this->queryBuilder->expr()->eq('sys_language_uid', 0)
124  );
125  }
126  if (isset(‪$config['addWhere'])) {
127  $this->queryBuilder->andWhere(
129  );
130  }
131  }
132 
145  public function ‪queryTable(&‪$params, $recursionCounter = 0)
146  {
147  $maxQueryResults = 50;
148  $rows = [];
149  $this->params = &‪$params;
150  $start = $recursionCounter * $maxQueryResults;
151  $this->‪prepareSelectStatement();
152 
153  $selectQueryBuilder = clone ‪$this->queryBuilder;
154  $selectQueryBuilder = $this->‪prepareOrderByStatement($selectQueryBuilder);
155  $result = $selectQueryBuilder->select($this->table . '.*')
156  ->from($this->table)
157  ->setFirstResult($start)
158  ->setMaxResults($maxQueryResults)
159  ->executeQuery();
160 
161  $countQueryBuilder = clone ‪$this->queryBuilder;
162  $allRowsCount = $countQueryBuilder
163  ->count($this->table . '.uid')
164  ->from($this->table)
165  ->executeQuery()
166  ->fetchOne();
167  if ($allRowsCount) {
168  while ($row = $result->fetchAssociative()) {
169  // check if we already have collected the maximum number of records
170  if (count($rows) > $this->maxItems) {
171  break;
172  }
173  $this->‪manipulateRecord($row);
174  $this->‪makeWorkspaceOverlay($row);
175  // check if the user has access to the record
176  if (!$this->‪checkRecordAccess($row, $row['uid'])) {
177  continue;
178  }
179  $icon = $this->iconFactory->getIconForRecord($this->table, $row, IconSize::SMALL);
180  ‪$uid = ($row['t3ver_oid'] ?? 0) > 0 ? $row['t3ver_oid'] : $row['uid'];
181  $path = $this->‪getRecordPath($row, ‪$uid);
182  $label = $this->‪getLabel($row);
183  $entry = [
184  'table' => $this->mmForeignTable ?: ‪$this->table,
185  'label' => strip_tags($label),
186  'path' => $path,
187  'uid' => ‪$uid,
188  'icon' => [
189  'identifier' => $icon->getIdentifier(),
190  'overlay' => $icon->getOverlayIcon()?->getIdentifier(),
191  ],
192  ];
193  $rows[$this->table . '_' . ‪$uid] = $this->‪renderRecord($row, $entry);
194  }
195 
196  // if there are less records than we need, call this function again to get more records
197  if (count($rows) < $this->maxItems && $allRowsCount >= $maxQueryResults && $recursionCounter < $this->maxItems) {
198  $tmp = ‪self::queryTable(‪$params, ++$recursionCounter);
199  $rows = array_merge($tmp, $rows);
200  }
201  }
202  return $rows;
203  }
204 
209  protected function ‪prepareSelectStatement()
210  {
211  $expressionBuilder = $this->queryBuilder->expr();
212  $searchString = $this->params['value'];
213  if ($searchString !== '') {
214  $splitStrings = $this->‪splitSearchString($searchString);
215  $constraints = [];
216  foreach ($splitStrings as $splitString) {
217  $constraints[] = $this->‪buildConstraintBlock($splitString);
218  }
219  foreach ($constraints as $constraint) {
220  $this->queryBuilder->andWhere($expressionBuilder->and($constraint));
221  }
222  }
223  if (!empty($this->allowedPages)) {
224  $pidList = array_map(intval(...), $this->allowedPages);
225  if (!empty($pidList)) {
226  $this->queryBuilder->andWhere(
227  $expressionBuilder->in('pid', $pidList)
228  );
229  }
230  }
231  // add an additional search condition comment
232  if (isset($this->config['searchCondition']) && $this->config['searchCondition'] !== '') {
233  $this->queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($this->config['searchCondition']));
234  }
235  }
236 
242  protected function ‪buildConstraintBlock(string $searchString)
243  {
244  $expressionBuilder = $this->queryBuilder->expr();
245  $selectParts = $expressionBuilder->or();
246  if (‪MathUtility::canBeInterpretedAsInteger($searchString) && (int)$searchString > 0) {
247  $selectParts = $selectParts->with($expressionBuilder->eq('uid', (int)$searchString));
248  }
249  $searchWholePhrase = !isset($this->config['searchWholePhrase']) || $this->config['searchWholePhrase'];
250  $likeCondition = ($searchWholePhrase ? '%' : '') . $this->queryBuilder->escapeLikeWildcards($searchString) . '%';
251  // Search in all fields given by label or label_alt
252  $selectFieldsList = (‪$GLOBALS['TCA'][‪$this->table]['ctrl']['label'] ?? '') . ',' . (‪$GLOBALS['TCA'][$this->table]['ctrl']['label_alt'] ?? '') . ',' . ($this->config['additionalSearchFields'] ?? '');
253  $selectFields = ‪GeneralUtility::trimExplode(',', $selectFieldsList, true);
254  $selectFields = array_unique($selectFields);
255  foreach ($selectFields as $field) {
256  $selectParts = $selectParts->with($expressionBuilder->like($field, $this->queryBuilder->createPositionalParameter($likeCondition)));
257  }
258 
259  return $selectParts;
260  }
261 
267  protected function ‪splitSearchString(string $searchString): array
268  {
269  return str_getcsv($searchString, ' ');
270  }
271 
279  protected function ‪getAvailablePageIds(array $entryPointPageIds, int $depth = 0): array
280  {
281  if ($depth === 0) {
282  return $entryPointPageIds;
283  }
284  $pageIds = [];
285  $repository = GeneralUtility::makeInstance(PageTreeRepository::class);
286  $pages = $repository->getFlattenedPages($entryPointPageIds, $depth);
287  foreach ($pages as $page) {
288  $pageIds[] = (int)$page['uid'];
289  }
290  return $pageIds;
291  }
292 
297  protected function ‪prepareOrderByStatement(QueryBuilder ‪$queryBuilder): QueryBuilder
298  {
299  if (empty($this->config['orderBy'])) {
300  ‪$queryBuilder->addOrderBy(‪$GLOBALS['TCA'][$this->table]['ctrl']['label']);
301  } else {
302  foreach (‪QueryHelper::parseOrderBy($this->config['orderBy']) as $orderPair) {
303  [$fieldName, $order] = $orderPair;
304  ‪$queryBuilder->addOrderBy($fieldName, $order);
305  }
306  }
308  }
309 
315  protected function ‪manipulateRecord(&$row) {}
316 
324  protected function ‪checkRecordAccess($row, ‪$uid)
325  {
326  $backendUser = $this->‪getBackendUser();
327  $retValue = true;
328  ‪$table = $this->mmForeignTable ?: ‪$this->table;
329  if (‪$table === 'pages') {
330  if (!BackendUtility::readPageAccess(‪$uid, $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW))) {
331  $retValue = false;
332  }
333  } elseif (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['is_static']) && (bool)‪$GLOBALS['TCA'][‪$table]['ctrl']['is_static']) {
334  $retValue = true;
335  } else {
336  if (!is_array(BackendUtility::readPageAccess($row['pid'], $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW)))) {
337  $retValue = false;
338  }
339  }
340  return $retValue;
341  }
342 
348  protected function ‪makeWorkspaceOverlay(&$row)
349  {
350  // Check for workspace-versions
351  if ($this->‪getBackendUser()->workspace !== 0 && BackendUtility::isTableWorkspaceEnabled($this->table)) {
352  BackendUtility::workspaceOL($this->mmForeignTable ?: $this->table, $row);
353  }
354  }
355 
366  protected function ‪getRecordPath(&$row, ‪$uid)
367  {
368  $titleLimit = max($this->config['maxPathTitleLength'] ?? 0, 0);
369  if (($this->mmForeignTable ?: $this->table) === 'pages') {
370  $path = BackendUtility::getRecordPath(‪$uid, '', $titleLimit);
371  // For pages we only want the first (n-1) parts of the path,
372  // because the n-th part is the page itself
373  $path = substr($path, 0, (int)strrpos($path, '/', -2)) . '/';
374  } else {
375  $path = BackendUtility::getRecordPath($row['pid'], '', $titleLimit);
376  }
377  return $path;
378  }
379 
386  protected function ‪getLabel($row)
387  {
388  return BackendUtility::getRecordTitle($this->mmForeignTable ?: $this->table, $row, true);
389  }
390 
400  protected function ‪renderRecord($row, $entry)
401  {
402  // Call renderlet if available (normal pages etc. usually don't have one)
403  if (($this->config['renderFunc'] ?? '') != '') {
404  ‪$params = [
405  'table' => ‪$this->table,
406  'uid' => $row['uid'],
407  'row' => $row,
408  'entry' => &$entry,
409  ];
410  GeneralUtility::callUserFunction($this->config['renderFunc'], ‪$params, $this);
411  }
412  return $entry;
413  }
414 
415  protected function ‪getLanguageService(): ‪LanguageService
416  {
417  return ‪$GLOBALS['LANG'];
418  }
419 
421  {
422  return ‪$GLOBALS['BE_USER'];
423  }
424 
429  protected function ‪getQueryBuilderForTable(‪$table)
430  {
431  return GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
432  }
433 }
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseOrderBy
‪static array array[] parseOrderBy(string $input)
Definition: QueryHelper.php:44
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$config
‪array $config
Definition: SuggestWizardDefaultReceiver.php:58
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getRecordPath
‪string getRecordPath(&$row, $uid)
Definition: SuggestWizardDefaultReceiver.php:358
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getAvailablePageIds
‪array getAvailablePageIds(array $entryPointPageIds, int $depth=0)
Definition: SuggestWizardDefaultReceiver.php:271
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\renderRecord
‪array renderRecord($row, $entry)
Definition: SuggestWizardDefaultReceiver.php:392
‪TYPO3\CMS\Backend\Form\Wizard
Definition: SuggestWizardDefaultReceiver.php:16
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:35
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\makeWorkspaceOverlay
‪makeWorkspaceOverlay(&$row)
Definition: SuggestWizardDefaultReceiver.php:340
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$iconFactory
‪IconFactory $iconFactory
Definition: SuggestWizardDefaultReceiver.php:78
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\queryTable
‪array queryTable(&$params, $recursionCounter=0)
Definition: SuggestWizardDefaultReceiver.php:137
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getQueryBuilderForTable
‪QueryBuilder getQueryBuilderForTable($table)
Definition: SuggestWizardDefaultReceiver.php:421
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$mmForeignTable
‪string $mmForeignTable
Definition: SuggestWizardDefaultReceiver.php:52
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:27
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\splitSearchString
‪splitSearchString(string $searchString)
Definition: SuggestWizardDefaultReceiver.php:259
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$params
‪array $params
Definition: SuggestWizardDefaultReceiver.php:74
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$queryBuilder
‪QueryBuilder $queryBuilder
Definition: SuggestWizardDefaultReceiver.php:82
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getLabel
‪string getLabel($row)
Definition: SuggestWizardDefaultReceiver.php:378
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:35
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\checkRecordAccess
‪bool checkRecordAccess($row, $uid)
Definition: SuggestWizardDefaultReceiver.php:316
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getLanguageService
‪getLanguageService()
Definition: SuggestWizardDefaultReceiver.php:407
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$allowedPages
‪array $allowedPages
Definition: SuggestWizardDefaultReceiver.php:64
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$table
‪string $table
Definition: SuggestWizardDefaultReceiver.php:45
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:171
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getBackendUser
‪getBackendUser()
Definition: SuggestWizardDefaultReceiver.php:412
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository
Definition: PageTreeRepository.php:41
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\prepareSelectStatement
‪prepareSelectStatement()
Definition: SuggestWizardDefaultReceiver.php:201
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\prepareOrderByStatement
‪prepareOrderByStatement(QueryBuilder $queryBuilder)
Definition: SuggestWizardDefaultReceiver.php:289
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$maxItems
‪int $maxItems
Definition: SuggestWizardDefaultReceiver.php:70
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\manipulateRecord
‪manipulateRecord(&$row)
Definition: SuggestWizardDefaultReceiver.php:307
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver
Definition: SuggestWizardDefaultReceiver.php:40
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\buildConstraintBlock
‪string TYPO3 CMS Core Database Query Expression CompositeExpression buildConstraintBlock(string $searchString)
Definition: SuggestWizardDefaultReceiver.php:234
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\__construct
‪__construct($table, $config)
Definition: SuggestWizardDefaultReceiver.php:90
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39