TYPO3 CMS  TYPO3_8-7
SuggestWizardDefaultReceiver.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
28 
36 {
42  protected $table = '';
43 
50  protected $mmForeignTable = '';
51 
57  protected $config = [];
58 
64  protected $allowedPages = [];
65 
71  protected $maxItems = 10;
72 
76  protected $params = [];
77 
81  protected $iconFactory;
82 
86  protected $queryBuilder;
87 
94  public function __construct($table, $config)
95  {
96  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
97  $this->queryBuilder = $this->getQueryBuilderForTable($table);
98  $this->queryBuilder->getRestrictions()
99  ->removeAll()
100  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
101  // if table is versionized, only get the records from the Live Workspace
102  // the overlay itself of WS-records is done below
103  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class, 0));
104  $this->table = $table;
105  $this->config = $config;
106  // get a list of all the pages that should be looked on
107  if (isset($config['pidList'])) {
108  $allowedPages = ($pageIds = GeneralUtility::trimExplode(',', $config['pidList']));
109  $depth = (int)$config['pidDepth'];
110  foreach ($pageIds as $pageId) {
111  if ($pageId > 0) {
113  }
114  }
115  $this->allowedPages = array_unique($allowedPages);
116  }
117  if (isset($config['maxItemsInResultList'])) {
118  $this->maxItems = $config['maxItemsInResultList'];
119  }
120  if ($this->table === 'pages') {
121  $this->queryBuilder->andWhere(
122  QueryHelper::stripLogicalOperatorPrefix($GLOBALS['BE_USER']->getPagePermsClause(1))
123  );
124  }
125  if (isset($config['addWhere'])) {
126  $this->queryBuilder->andWhere(
128  );
129  }
130  }
131 
144  public function queryTable(&$params, $recursionCounter = 0)
145  {
146  $rows = [];
147  $this->params = &$params;
148  $start = $recursionCounter * 50;
149  $this->prepareSelectStatement();
150  $this->prepareOrderByStatement();
151  $result = $this->queryBuilder->select('*')
152  ->from($this->table)
153  ->setFirstResult($start)
154  ->setMaxResults(50)
155  ->execute();
156  $allRowsCount = $result->rowCount();
157  if ($allRowsCount) {
158  while ($row = $result->fetch()) {
159  // check if we already have collected the maximum number of records
160  if (count($rows) > $this->maxItems) {
161  break;
162  }
163  $this->manipulateRecord($row);
164  $this->makeWorkspaceOverlay($row);
165  // check if the user has access to the record
166  if (!$this->checkRecordAccess($row, $row['uid'])) {
167  continue;
168  }
169  $spriteIcon = $this->iconFactory->getIconForRecord($this->table, $row, Icon::SIZE_SMALL)->render();
170  $uid = $row['t3ver_oid'] > 0 ? $row['t3ver_oid'] : $row['uid'];
171  $path = $this->getRecordPath($row, $uid);
172  if (mb_strlen($path, 'utf-8') > 30) {
173  $croppedPath = '<abbr title="' . htmlspecialchars($path) . '">' .
174  htmlspecialchars(
175  mb_substr($path, 0, 10, 'utf-8')
176  . '...'
177  . mb_substr($path, -20, null, 'utf-8')
178  ) .
179  '</abbr>';
180  } else {
181  $croppedPath = htmlspecialchars($path);
182  }
183  $label = $this->getLabel($row);
184  $entry = [
185  'text' => '<span class="suggest-label">' . $label . '</span><span class="suggest-uid">[' . $uid . ']</span><br />
186  <span class="suggest-path">' . $croppedPath . '</span>',
187  'table' => $this->mmForeignTable ? $this->mmForeignTable : $this->table,
188  'label' => $label,
189  'path' => $path,
190  'uid' => $uid,
191  'style' => '',
192  'class' => isset($this->config['cssClass']) ? $this->config['cssClass'] : '',
193  'sprite' => $spriteIcon
194  ];
195  $rows[$this->table . '_' . $uid] = $this->renderRecord($row, $entry);
196  }
197 
198  // if there are less records than we need, call this function again to get more records
199  if (count($rows) < $this->maxItems && $allRowsCount >= 50 && $recursionCounter < $this->maxItems) {
200  $tmp = self::queryTable($params, ++$recursionCounter);
201  $rows = array_merge($tmp, $rows);
202  }
203  }
204  return $rows;
205  }
206 
211  protected function prepareSelectStatement()
212  {
213  $expressionBuilder = $this->queryBuilder->expr();
214  $searchWholePhrase = !isset($this->config['searchWholePhrase']) || $this->config['searchWholePhrase'];
215  $searchString = $this->params['value'];
216  $searchUid = (int)$searchString;
217  if ($searchString !== '') {
218  $likeCondition = ($searchWholePhrase ? '%' : '') . $searchString . '%';
219  // Search in all fields given by label or label_alt
220  $selectFieldsList = $GLOBALS['TCA'][$this->table]['ctrl']['label'] . ',' . $GLOBALS['TCA'][$this->table]['ctrl']['label_alt'] . ',' . $this->config['additionalSearchFields'];
221  $selectFields = GeneralUtility::trimExplode(',', $selectFieldsList, true);
222  $selectFields = array_unique($selectFields);
223  $selectParts = $expressionBuilder->orX();
224  foreach ($selectFields as $field) {
225  $selectParts->add($expressionBuilder->like($field, $this->queryBuilder->createPositionalParameter($likeCondition)));
226  }
227 
228  $searchClause = $expressionBuilder->orX($selectParts);
229  if ($searchUid > 0 && $searchUid == $searchString) {
230  $searchClause->add($expressionBuilder->eq('uid', $searchUid));
231  }
232 
233  $this->queryBuilder->andWhere($expressionBuilder->orX($searchClause));
234  }
235  if (!empty($this->allowedPages)) {
236  $pidList = array_map('intval', $this->allowedPages);
237  if (!empty($pidList)) {
238  $this->queryBuilder->andWhere(
239  $expressionBuilder->in('pid', $pidList)
240  );
241  }
242  }
243  // add an additional search condition comment
244  if (isset($this->config['searchCondition']) && $this->config['searchCondition'] !== '') {
245  $this->queryBuilder->andWhere(QueryHelper::stripLogicalOperatorPrefix($this->config['searchCondition']));
246  }
247  }
248 
256  protected function getAllSubpagesOfPage($uid, $depth = 99)
257  {
258  $pageIds = [$uid];
259  $level = 0;
260  $pages = [$uid];
261  $queryBuilder = $this->getQueryBuilderForTable('pages');
262  $queryBuilder->select('uid')
263  ->from('pages');
264  // fetch all
265  while ($depth - $level > 0 && !empty($pageIds)) {
266  ++$level;
267  $rows = $queryBuilder
268  ->where(
269  $queryBuilder->expr()->in(
270  'pid',
271  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
272  )
273  )
274  ->execute()
275  ->fetchAll();
276 
277  $rows = array_column(($rows ?: []), 'uid', 'uid');
278  if (!count($rows)) {
279  break;
280  }
281 
282  $pageIds = array_keys($rows);
283  $pages = array_merge($pages, $pageIds);
284  }
285  return $pages;
286  }
287 
292  protected function prepareOrderByStatement()
293  {
294  if (empty($this->config['orderBy'])) {
295  $this->queryBuilder->addOrderBy($GLOBALS['TCA'][$this->table]['ctrl']['label']);
296  } else {
297  foreach (QueryHelper::parseOrderBy($this->config['orderBy']) as $orderPair) {
298  list($fieldName, $order) = $orderPair;
299  $this->queryBuilder->addOrderBy($fieldName, $order);
300  }
301  }
302  }
303 
309  protected function manipulateRecord(&$row)
310  {
311  }
312 
320  protected function checkRecordAccess($row, $uid)
321  {
322  $retValue = true;
323  $table = $this->mmForeignTable ?: $this->table;
324  if ($table === 'pages') {
325  if (!BackendUtility::readPageAccess($uid, $GLOBALS['BE_USER']->getPagePermsClause(1))) {
326  $retValue = false;
327  }
328  } elseif (isset($GLOBALS['TCA'][$table]['ctrl']['is_static']) && (bool)$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
329  $retValue = true;
330  } else {
331  if (!is_array(BackendUtility::readPageAccess($row['pid'], $GLOBALS['BE_USER']->getPagePermsClause(1)))) {
332  $retValue = false;
333  }
334  }
335  return $retValue;
336  }
337 
343  protected function makeWorkspaceOverlay(&$row)
344  {
345  // Check for workspace-versions
346  if ($GLOBALS['BE_USER']->workspace != 0 && $GLOBALS['TCA'][$this->table]['ctrl']['versioningWS'] == true) {
347  BackendUtility::workspaceOL($this->mmForeignTable ? $this->mmForeignTable : $this->table, $row);
348  }
349  }
350 
361  protected function getRecordPath(&$row, $uid)
362  {
363  $titleLimit = max($this->config['maxPathTitleLength'], 0);
364  if (($this->mmForeignTable ? $this->mmForeignTable : $this->table) === 'pages') {
365  $path = BackendUtility::getRecordPath($uid, '', $titleLimit);
366  // For pages we only want the first (n-1) parts of the path,
367  // because the n-th part is the page itself
368  $path = substr($path, 0, strrpos($path, '/', -2)) . '/';
369  } else {
370  $path = BackendUtility::getRecordPath($row['pid'], '', $titleLimit);
371  }
372  return $path;
373  }
374 
381  protected function getLabel($row)
382  {
383  return BackendUtility::getRecordTitle($this->mmForeignTable ? $this->mmForeignTable : $this->table, $row, true);
384  }
385 
395  protected function renderRecord($row, $entry)
396  {
397  // Call renderlet if available (normal pages etc. usually don't have one)
398  if ($this->config['renderFunc'] != '') {
399  $params = [
400  'table' => $this->table,
401  'uid' => $row['uid'],
402  'row' => $row,
403  'entry' => &$entry
404  ];
405  GeneralUtility::callUserFunction($this->config['renderFunc'], $params, $this);
406  }
407  return $entry;
408  }
409 
413  protected function getLanguageService()
414  {
415  return $GLOBALS['LANG'];
416  }
417 
422  protected function getQueryBuilderForTable($table)
423  {
424  return GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
425  }
426 }
static readPageAccess($id, $perms_clause)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static makeInstance($className,... $constructorArguments)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static stripLogicalOperatorPrefix(string $constraint)
static getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']