‪TYPO3CMS  10.4
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 
31 
39 {
45  protected ‪$table = '';
46 
53  protected ‪$mmForeignTable = '';
54 
60  protected ‪$config = [];
61 
67  protected ‪$allowedPages = [];
68 
74  protected ‪$maxItems = 10;
75 
79  protected ‪$params = [];
80 
84  protected ‪$iconFactory;
85 
89  protected ‪$queryBuilder;
90 
97  public function ‪__construct(‪$table, ‪$config)
98  {
99  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
100  $this->queryBuilder = $this->‪getQueryBuilderForTable(‪$table);
101  $this->queryBuilder->getRestrictions()
102  ->removeAll()
103  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
104  // if table is versionized, only get the records from the Live Workspace
105  // the overlay itself of WS-records is done below
106  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, 0));
107  $this->table = ‪$table;
108  $this->config = ‪$config;
109  // get a list of all the pages that should be looked on
110  if (isset(‪$config['pidList'])) {
111  $pageIds = ‪GeneralUtility::intExplode(',', ‪$config['pidList'], true);
112  $depth = (int)(‪$config['pidDepth'] ?? 0);
113  $availablePageIds = [];
114  foreach ($pageIds as $pageId) {
115  $availablePageIds[] = $this->‪getAvailablePageIds($pageId, $depth);
116  }
117  $this->allowedPages = array_unique(array_merge($this->allowedPages, ...$availablePageIds));
118  }
119  if (isset(‪$config['maxItemsInResultList'])) {
120  $this->maxItems = ‪$config['maxItemsInResultList'];
121  }
122  ‪$GLOBALS['BE_USER']->initializeWebmountsForElementBrowser();
123  if ($this->table === 'pages') {
124  $this->queryBuilder->andWhere(
126  $this->queryBuilder->expr()->eq('sys_language_uid', 0)
127  );
128  }
129  if (isset(‪$config['addWhere'])) {
130  $this->queryBuilder->andWhere(
132  );
133  }
134  }
135 
148  public function ‪queryTable(&‪$params, $recursionCounter = 0)
149  {
150  $maxQueryResults = 50;
151  $rows = [];
152  $this->params = &‪$params;
153  $start = $recursionCounter * $maxQueryResults;
154  $this->‪prepareSelectStatement();
156  $result = $this->queryBuilder->select('*')
157  ->from($this->table)
158  ->setFirstResult($start)
159  ->setMaxResults($maxQueryResults)
160  ->execute();
161  $allRowsCount = $this->queryBuilder
162  ->count('uid')
163  ->resetQueryPart('orderBy')
164  ->execute()
165  ->fetchColumn(0);
166  if ($allRowsCount) {
167  while ($row = $result->fetch()) {
168  // check if we already have collected the maximum number of records
169  if (count($rows) > $this->maxItems) {
170  break;
171  }
172  $this->‪manipulateRecord($row);
173  $this->‪makeWorkspaceOverlay($row);
174  // check if the user has access to the record
175  if (!$this->‪checkRecordAccess($row, $row['uid'])) {
176  continue;
177  }
178  $spriteIcon = $this->iconFactory->getIconForRecord($this->table, $row, ‪Icon::SIZE_SMALL)->render();
179  $uid = $row['t3ver_oid'] > 0 ? $row['t3ver_oid'] : $row['uid'];
180  $path = $this->‪getRecordPath($row, $uid);
181  if (mb_strlen($path, 'utf-8') > 30) {
182  $croppedPath = '<abbr title="' . htmlspecialchars($path) . '">' .
183  htmlspecialchars(
184  mb_substr($path, 0, 10, 'utf-8')
185  . '...'
186  . mb_substr($path, -20, null, 'utf-8')
187  ) .
188  '</abbr>';
189  } else {
190  $croppedPath = htmlspecialchars($path);
191  }
192  $label = $this->‪getLabel($row);
193  $entry = [
194  'text' => '<span class="suggest-label">' . $label . '</span><span class="suggest-uid">[' . $uid . ']</span><br />
195  <span class="suggest-path">' . $croppedPath . '</span>',
196  'table' => $this->mmForeignTable ?: ‪$this->table,
197  'label' => strip_tags($label),
198  'path' => $path,
199  'uid' => $uid,
200  'style' => '',
201  'class' => $this->config['cssClass'] ?? '',
202  'sprite' => $spriteIcon
203  ];
204  $rows[$this->table . '_' . $uid] = $this->‪renderRecord($row, $entry);
205  }
206 
207  // if there are less records than we need, call this function again to get more records
208  if (count($rows) < $this->maxItems && $allRowsCount >= $maxQueryResults && $recursionCounter < $this->maxItems) {
209  $tmp = ‪self::queryTable(‪$params, ++$recursionCounter);
210  $rows = array_merge($tmp, $rows);
211  }
212  }
213  return $rows;
214  }
215 
220  protected function ‪prepareSelectStatement()
221  {
222  $expressionBuilder = $this->queryBuilder->expr();
223  $searchString = $this->params['value'];
224  if ($searchString !== '') {
225  $splitStrings = $this->‪splitSearchString($searchString);
226  $constraints = [];
227  foreach ($splitStrings as $splitString) {
228  $constraints[] = $this->‪buildConstraintBlock($splitString);
229  }
230  foreach ($constraints as $constraint) {
231  $this->queryBuilder->andWhere($expressionBuilder->andX($constraint));
232  }
233  }
234  if (!empty($this->allowedPages)) {
235  $pidList = array_map('intval', $this->allowedPages);
236  if (!empty($pidList)) {
237  $this->queryBuilder->andWhere(
238  $expressionBuilder->in('pid', $pidList)
239  );
240  }
241  }
242  // add an additional search condition comment
243  if (isset($this->config['searchCondition']) && $this->config['searchCondition'] !== '') {
244  $this->queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($this->config['searchCondition']));
245  }
246  }
247 
254  protected function ‪buildConstraintBlock(string $searchString)
255  {
256  $expressionBuilder = $this->queryBuilder->expr();
257  $selectParts = $expressionBuilder->orX();
258  if (‪MathUtility::canBeInterpretedAsInteger($searchString) && (int)$searchString > 0) {
259  $selectParts->add($expressionBuilder->eq('uid', (int)$searchString));
260  }
261  $searchWholePhrase = !isset($this->config['searchWholePhrase']) || $this->config['searchWholePhrase'];
262  $likeCondition = ($searchWholePhrase ? '%' : '') . $this->queryBuilder->escapeLikeWildcards($searchString) . '%';
263  // Search in all fields given by label or label_alt
264  $selectFieldsList = (‪$GLOBALS['TCA'][‪$this->table]['ctrl']['label'] ?? '') . ',' . (‪$GLOBALS['TCA'][$this->table]['ctrl']['label_alt'] ?? '') . ',' . $this->config['additionalSearchFields'];
265  $selectFields = ‪GeneralUtility::trimExplode(',', $selectFieldsList, true);
266  $selectFields = array_unique($selectFields);
267  foreach ($selectFields as $field) {
268  $selectParts->add($expressionBuilder->like($field, $this->queryBuilder->createPositionalParameter($likeCondition)));
269  }
270 
271  return $selectParts;
272  }
273 
282  protected function ‪splitSearchString(string $searchString): array
283  {
284  return str_getcsv($searchString, ' ');
285  }
286 
294  protected function ‪getAvailablePageIds(int $id, int $depth = 0): array
295  {
296  if ($depth === 0) {
297  return [$id];
298  }
299  $tree = GeneralUtility::makeInstance(PageTreeView::class);
300  $tree->init();
301  $tree->getTree($id, $depth);
302  $tree->makeHTML = 0;
303  $tree->fieldArray = ['uid'];
304  $tree->ids[] = $id;
305  return $tree->ids;
306  }
307 
312  protected function ‪prepareOrderByStatement()
313  {
314  if (empty($this->config['orderBy'])) {
315  $this->queryBuilder->addOrderBy(‪$GLOBALS['TCA'][$this->table]['ctrl']['label']);
316  } else {
317  foreach (‪QueryHelper::parseOrderBy($this->config['orderBy']) as $orderPair) {
318  [$fieldName, $order] = $orderPair;
319  $this->queryBuilder->addOrderBy($fieldName, $order);
320  }
321  }
322  }
323 
329  protected function ‪manipulateRecord(&$row)
330  {
331  }
332 
340  protected function ‪checkRecordAccess($row, $uid)
341  {
342  $retValue = true;
343  ‪$table = $this->mmForeignTable ?: ‪$this->table;
344  if (‪$table === 'pages') {
345  if (!‪BackendUtility::readPageAccess($uid, ‪$GLOBALS['BE_USER']->getPagePermsClause(‪Permission::PAGE_SHOW))) {
346  $retValue = false;
347  }
348  } elseif (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['is_static']) && (bool)‪$GLOBALS['TCA'][‪$table]['ctrl']['is_static']) {
349  $retValue = true;
350  } else {
351  if (!is_array(‪BackendUtility::readPageAccess($row['pid'], ‪$GLOBALS['BE_USER']->getPagePermsClause(‪Permission::PAGE_SHOW)))) {
352  $retValue = false;
353  }
354  }
355  return $retValue;
356  }
357 
363  protected function ‪makeWorkspaceOverlay(&$row)
364  {
365  // Check for workspace-versions
366  if (‪$GLOBALS['BE_USER']->workspace != 0 && ‪BackendUtility::isTableWorkspaceEnabled($this->table)) {
367  ‪BackendUtility::workspaceOL($this->mmForeignTable ?: $this->table, $row);
368  }
369  }
370 
381  protected function ‪getRecordPath(&$row, $uid)
382  {
383  $titleLimit = max($this->config['maxPathTitleLength'], 0);
384  if (($this->mmForeignTable ?: $this->table) === 'pages') {
385  $path = ‪BackendUtility::getRecordPath($uid, '', $titleLimit);
386  // For pages we only want the first (n-1) parts of the path,
387  // because the n-th part is the page itself
388  $path = substr($path, 0, (int)strrpos($path, '/', -2)) . '/';
389  } else {
390  $path = ‪BackendUtility::getRecordPath($row['pid'], '', $titleLimit);
391  }
392  return $path;
393  }
394 
401  protected function ‪getLabel($row)
402  {
403  return ‪BackendUtility::getRecordTitle($this->mmForeignTable ?: $this->table, $row, true);
404  }
405 
415  protected function ‪renderRecord($row, $entry)
416  {
417  // Call renderlet if available (normal pages etc. usually don't have one)
418  if ($this->config['renderFunc'] != '') {
419  ‪$params = [
420  'table' => ‪$this->table,
421  'uid' => $row['uid'],
422  'row' => $row,
423  'entry' => &$entry
424  ];
425  GeneralUtility::callUserFunction($this->config['renderFunc'], ‪$params, $this);
426  }
427  return $entry;
428  }
429 
433  protected function ‪getLanguageService()
434  {
435  return ‪$GLOBALS['LANG'];
436  }
437 
442  protected function ‪getQueryBuilderForTable(‪$table)
443  {
444  return GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
445  }
446 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪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:57
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getRecordPath
‪string getRecordPath(&$row, $uid)
Definition: SuggestWizardDefaultReceiver.php:373
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\renderRecord
‪array renderRecord($row, $entry)
Definition: SuggestWizardDefaultReceiver.php:407
‪TYPO3\CMS\Backend\Form\Wizard
Definition: SuggestWizardDefaultReceiver.php:16
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\splitSearchString
‪array splitSearchString(string $searchString)
Definition: SuggestWizardDefaultReceiver.php:274
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:33
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\makeWorkspaceOverlay
‪makeWorkspaceOverlay(&$row)
Definition: SuggestWizardDefaultReceiver.php:355
‪TYPO3\CMS\Backend\Tree\View\PageTreeView
Definition: PageTreeView.php:24
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:24
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$iconFactory
‪IconFactory $iconFactory
Definition: SuggestWizardDefaultReceiver.php:77
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:52
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getLanguageService
‪LanguageService getLanguageService()
Definition: SuggestWizardDefaultReceiver.php:425
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\queryTable
‪array queryTable(&$params, $recursionCounter=0)
Definition: SuggestWizardDefaultReceiver.php:140
‪TYPO3\CMS\Backend\Utility\BackendUtility\isTableWorkspaceEnabled
‪static bool isTableWorkspaceEnabled($table)
Definition: BackendUtility.php:4021
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getAvailablePageIds
‪array getAvailablePageIds(int $id, int $depth=0)
Definition: SuggestWizardDefaultReceiver.php:286
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getQueryBuilderForTable
‪QueryBuilder getQueryBuilderForTable($table)
Definition: SuggestWizardDefaultReceiver.php:434
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$mmForeignTable
‪string $mmForeignTable
Definition: SuggestWizardDefaultReceiver.php:51
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:25
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$params
‪array $params
Definition: SuggestWizardDefaultReceiver.php:73
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$queryBuilder
‪QueryBuilder $queryBuilder
Definition: SuggestWizardDefaultReceiver.php:81
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordTitle
‪static string getRecordTitle($table, $row, $prep=false, $forceResult=true)
Definition: BackendUtility.php:1541
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\prepareOrderByStatement
‪prepareOrderByStatement()
Definition: SuggestWizardDefaultReceiver.php:304
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\getLabel
‪string getLabel($row)
Definition: SuggestWizardDefaultReceiver.php:393
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:33
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\checkRecordAccess
‪bool checkRecordAccess($row, $uid)
Definition: SuggestWizardDefaultReceiver.php:332
‪TYPO3\CMS\Backend\Utility\BackendUtility\readPageAccess
‪static array false readPageAccess($id, $perms_clause)
Definition: BackendUtility.php:597
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$allowedPages
‪array $allowedPages
Definition: SuggestWizardDefaultReceiver.php:63
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$table
‪string $table
Definition: SuggestWizardDefaultReceiver.php:44
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:165
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Backend\Utility\BackendUtility\workspaceOL
‪static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
Definition: BackendUtility.php:3586
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\prepareSelectStatement
‪prepareSelectStatement()
Definition: SuggestWizardDefaultReceiver.php:212
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\$maxItems
‪int $maxItems
Definition: SuggestWizardDefaultReceiver.php:69
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordPath
‪static mixed getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
Definition: BackendUtility.php:546
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\manipulateRecord
‪manipulateRecord(&$row)
Definition: SuggestWizardDefaultReceiver.php:321
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver
Definition: SuggestWizardDefaultReceiver.php:39
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\buildConstraintBlock
‪string TYPO3 CMS Core Database Query Expression CompositeExpression buildConstraintBlock(string $searchString)
Definition: SuggestWizardDefaultReceiver.php:246
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver\__construct
‪__construct($table, $config)
Definition: SuggestWizardDefaultReceiver.php:89
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39