TYPO3 CMS  TYPO3_8-7
DataProvider.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 
25 
30 {
36  protected $nodeLimit = 0;
37 
43  protected $nodeCounter = 0;
44 
50  protected $showRootlineAboveMounts = false;
51 
57  protected $hiddenRecords = [];
58 
65 
71  public function __construct($nodeLimit = null)
72  {
73  if ($nodeLimit === null) {
74  $nodeLimit = $GLOBALS['TYPO3_CONF_VARS']['BE']['pageTree']['preloadLimit'];
75  }
76  $this->nodeLimit = abs((int)$nodeLimit);
77 
78  $this->showRootlineAboveMounts = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showPathAboveMounts');
79 
80  $this->hiddenRecords = GeneralUtility::trimExplode(',', $GLOBALS['BE_USER']->getTSConfigVal('options.hideRecords.pages'));
81  $hookElements = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/tree/pagetree/class.t3lib_tree_pagetree_dataprovider.php']['postProcessCollections'];
82  if (is_array($hookElements)) {
83  foreach ($hookElements as $classRef) {
85  $hookObject = GeneralUtility::getUserObj($classRef);
86  if ($hookObject instanceof \TYPO3\CMS\Backend\Tree\Pagetree\CollectionProcessorInterface) {
87  $this->processCollectionHookObjects[] = $hookObject;
88  }
89  }
90  }
91  }
92 
98  public function getRoot()
99  {
101  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode::class);
102  $node->setId('root');
103  $node->setExpanded(true);
104  return $node;
105  }
106 
115  public function getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node, $mountPoint = 0, $level = 0)
116  {
118  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
119  if ($level >= 99 || $node->getStopPageTree()) {
120  return $nodeCollection;
121  }
122  $isVirtualRootNode = false;
123  $subpages = $this->getSubpages($node->getId());
124  // check if fetching subpages the "root"-page
125  // and in case of a virtual root return the mountpoints as virtual "subpages"
126  if ((int)$node->getId() === 0) {
127  // check no temporary mountpoint is used
128  if (!(int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint']) {
129  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
130  $mountPoints = array_unique($mountPoints);
131  if (!in_array(0, $mountPoints)) {
132  // using a virtual root node
133  // so then return the mount points here as "subpages" of the first node
134  $isVirtualRootNode = true;
135  $subpages = [];
136  foreach ($mountPoints as $webMountPoint) {
137  $subpages[] = [
138  'uid' => $webMountPoint,
139  'isMountPoint' => true
140  ];
141  }
142  }
143  }
144  }
145  if (is_array($subpages) && !empty($subpages)) {
146  $lastRootline = [];
147  foreach ($subpages as $subpage) {
148  if (in_array($subpage['uid'], $this->hiddenRecords)) {
149  continue;
150  }
151  // must be calculated above getRecordWithWorkspaceOverlay,
152  // because the information is lost otherwise
153  $isMountPoint = $subpage['isMountPoint'] === true;
154  if ($isVirtualRootNode) {
155  $mountPoint = (int)$subpage['uid'];
156  }
157  $subpage = $this->getRecordWithWorkspaceOverlay($subpage['uid'], true);
158  if (!$subpage) {
159  continue;
160  }
161  $subNode = Commands::getNewNode($subpage, $mountPoint);
162  $subNode->setIsMountPoint($isMountPoint);
163  if ($isMountPoint && $this->showRootlineAboveMounts) {
164  if ($subpage['pid'] > 0) {
165  $rootline = Commands::getMountPointPath($subpage['pid']);
166  } else {
167  $rootline = Commands::getMountPointPath($subpage['uid']);
168  }
169  if ($lastRootline !== $rootline) {
170  $subNode->setReadableRootline($rootline);
171  }
172  $lastRootline = $rootline;
173  }
174  if ($this->nodeCounter < $this->nodeLimit) {
175  $childNodes = $this->getNodes($subNode, $mountPoint, $level + 1);
176  $subNode->setChildNodes($childNodes);
177  $this->nodeCounter += $childNodes->count();
178  } else {
179  $subNode->setLeaf(!$this->hasNodeSubPages($subNode->getId()));
180  }
181  if (!$GLOBALS['BE_USER']->isAdmin() && (int)$subpage['editlock'] === 1) {
182  $subNode->setLabelIsEditable(false);
183  }
184  $nodeCollection->append($subNode);
185  }
186  }
187  foreach ($this->processCollectionHookObjects as $hookObject) {
189  $hookObject->postProcessGetNodes($node, $mountPoint, $level, $nodeCollection);
190  }
191  return $nodeCollection;
192  }
193 
201  protected function getRecordWithWorkspaceOverlay($uid, $unsetMovePointers = false)
202  {
203  return BackendUtility::getRecordWSOL('pages', $uid, '*', '', true, $unsetMovePointers);
204  }
205 
214  public function getFilteredNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node, $searchFilter, $mountPoint = 0)
215  {
217  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
218  $records = $this->getSubpages(-1, $searchFilter);
219  if (!is_array($records) || empty($records)) {
220  return $nodeCollection;
221  }
222  if (count($records) > 500) {
223  return $nodeCollection;
224  }
225  // check no temporary mountpoint is used
226  $mountPoints = (int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
227  if (!$mountPoints) {
228  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
229  $mountPoints = array_unique($mountPoints);
230  } else {
231  $mountPoints = [$mountPoints];
232  }
233  $isNumericSearchFilter = is_numeric($searchFilter) && $searchFilter > 0;
234  $searchFilterQuoted = preg_quote($searchFilter, '/');
235  $nodeId = (int)$node->getId();
236  $processedRecordIds = [];
237  foreach ($records as $record) {
238  if ((int)$record['t3ver_wsid'] !== (int)$GLOBALS['BE_USER']->workspace && (int)$record['t3ver_wsid'] !== 0) {
239  continue;
240  }
241  $liveVersion = BackendUtility::getLiveVersionOfRecord('pages', $record['uid'], 'uid');
242  if ($liveVersion !== null) {
243  $record = $liveVersion;
244  }
245 
246  $record = Commands::getNodeRecord($record['uid'], false);
247  if ((int)$record['pid'] === -1
248  || in_array($record['uid'], $this->hiddenRecords)
249  || in_array($record['uid'], $processedRecordIds)
250  ) {
251  continue;
252  }
253  $processedRecordIds[] = $record['uid'];
254 
255  $rootline = BackendUtility::BEgetRootLine($record['uid'], '', $GLOBALS['BE_USER']->workspace != 0);
256  $rootline = array_reverse($rootline);
257  if (!in_array(0, $mountPoints, true)) {
258  $isInsideMountPoints = false;
259  foreach ($rootline as $rootlineElement) {
260  if (in_array((int)$rootlineElement['uid'], $mountPoints, true)) {
261  $isInsideMountPoints = true;
262  break;
263  }
264  }
265  if (!$isInsideMountPoints) {
266  continue;
267  }
268  }
269  $reference = $nodeCollection;
270  $inFilteredRootline = false;
271  $amountOfRootlineElements = count($rootline);
272  for ($i = 0; $i < $amountOfRootlineElements; ++$i) {
273  $rootlineElement = $rootline[$i];
274  $rootlineElement['uid'] = (int)$rootlineElement['uid'];
275  $isInWebMount = (int)$GLOBALS['BE_USER']->isInWebMount($rootlineElement['uid']);
276  if (!$isInWebMount
277  || ($rootlineElement['uid'] === (int)$mountPoints[0]
278  && $rootlineElement['uid'] !== $isInWebMount)
279  ) {
280  continue;
281  }
282  if ((int)$rootlineElement['pid'] === $nodeId
283  || $rootlineElement['uid'] === $nodeId
284  || ($rootlineElement['uid'] === $isInWebMount
285  && in_array($rootlineElement['uid'], $mountPoints, true))
286  ) {
287  $inFilteredRootline = true;
288  }
289  if (!$inFilteredRootline || $rootlineElement['uid'] === $mountPoint) {
290  continue;
291  }
292  $rootlineElement = Commands::getNodeRecord($rootlineElement['uid'], false);
293  $ident = (int)$rootlineElement['sorting'] . (int)$rootlineElement['uid'];
294  if ($reference && $reference->offsetExists($ident)) {
296  $refNode = $reference->offsetGet($ident);
297  $refNode->setExpanded(true);
298  $refNode->setLeaf(false);
299  $reference = $refNode->getChildNodes();
300  if ($reference == null) {
301  $reference = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
302  $refNode->setChildNodes($reference);
303  }
304  } else {
305  $refNode = Commands::getNewNode($rootlineElement, $mountPoint);
306  $replacement = '<span class="typo3-pagetree-filteringTree-highlight">$1</span>';
307  if ($isNumericSearchFilter && (int)$rootlineElement['uid'] === (int)$searchFilter) {
308  $text = str_replace('$1', $refNode->getText(), $replacement);
309  } else {
310  $text = preg_replace('/(' . $searchFilterQuoted . ')/iu', $replacement, $refNode->getText());
311  }
312  $refNode->setText($text, $refNode->getTextSourceField(), $refNode->getPrefix(), $refNode->getSuffix());
314  $childCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
315  if ($i + 1 >= $amountOfRootlineElements) {
316  $childNodes = $this->getNodes($refNode, $mountPoint);
317  foreach ($childNodes as $childNode) {
319  $childRecord = $childNode->getRecord();
320  $childIdent = (int)$childRecord['sorting'] . (int)$childRecord['uid'];
321  $childCollection->offsetSet($childIdent, $childNode);
322  }
323  $refNode->setChildNodes($childNodes);
324  }
325  $refNode->setChildNodes($childCollection);
326  $reference->offsetSet($ident, $refNode);
327  $reference->ksort();
328  $reference = $childCollection;
329  }
330  }
331  }
332  foreach ($this->processCollectionHookObjects as $hookObject) {
334  $hookObject->postProcessFilteredNodes($node, $searchFilter, $mountPoint, $nodeCollection);
335  }
336  return $nodeCollection;
337  }
338 
347  public function getTreeMounts($searchFilter = '')
348  {
350  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
351  $isTemporaryMountPoint = false;
352  $rootNodeIsVirtual = false;
353  $mountPoints = (int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
354  if (!$mountPoints) {
355  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
356  $mountPoints = array_unique($mountPoints);
357  if (!in_array(0, $mountPoints)) {
358  $rootNodeIsVirtual = true;
359  // use a virtual root
360  // the real mountpoints will be fetched in getNodes() then
361  // since those will be the "subpages" of the virtual root
362  $mountPoints = [0];
363  }
364  } else {
365  $isTemporaryMountPoint = true;
366  $mountPoints = [$mountPoints];
367  }
368  if (empty($mountPoints)) {
369  return $nodeCollection;
370  }
371 
372  foreach ($mountPoints as $mountPoint) {
373  if ($mountPoint === 0) {
374  $sitename = 'TYPO3';
375  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] !== '') {
376  $sitename = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
377  }
378  $record = [
379  'uid' => 0,
380  'title' => $sitename
381  ];
382  $subNode = Commands::getNewNode($record);
383  $subNode->setLabelIsEditable(false);
384  if ($rootNodeIsVirtual) {
385  $subNode->setType('virtual_root');
386  $subNode->setIsDropTarget(false);
387  } else {
388  $subNode->setType('pages_root');
389  $subNode->setIsDropTarget(true);
390  }
391  } else {
392  if (in_array($mountPoint, $this->hiddenRecords)) {
393  continue;
394  }
395  $record = $this->getRecordWithWorkspaceOverlay($mountPoint);
396  if (!$record) {
397  continue;
398  }
399  $subNode = Commands::getNewNode($record, $mountPoint);
400  if ($this->showRootlineAboveMounts && !$isTemporaryMountPoint) {
401  $rootline = Commands::getMountPointPath($record['uid']);
402  $subNode->setReadableRootline($rootline);
403  }
404  }
405  if (count($mountPoints) <= 1) {
406  $subNode->setExpanded(true);
407  $subNode->setCls('typo3-pagetree-node-notExpandable');
408  }
409  $subNode->setIsMountPoint(true);
410  $subNode->setDraggable(false);
411  if ($searchFilter === '') {
412  $childNodes = $this->getNodes($subNode, $mountPoint);
413  } else {
414  $childNodes = $this->getFilteredNodes($subNode, $searchFilter, $mountPoint);
415  $subNode->setExpanded(true);
416  }
417  $subNode->setChildNodes($childNodes);
418  $nodeCollection->append($subNode);
419  }
420  foreach ($this->processCollectionHookObjects as $hookObject) {
422  $hookObject->postProcessGetTreeMounts($searchFilter, $nodeCollection);
423  }
424  return $nodeCollection;
425  }
426 
435  protected function setWhereClause(QueryBuilder $queryBuilder, $id, $searchFilter = ''): QueryBuilder
436  {
437  $expressionBuilder = $queryBuilder->expr();
438  $queryBuilder->where(
439  QueryHelper::stripLogicalOperatorPrefix($GLOBALS['BE_USER']->getPagePermsClause(1))
440  );
441 
442  if (is_numeric($id) && $id >= 0) {
443  $queryBuilder->andWhere(
444  $expressionBuilder->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT))
445  );
446  }
447 
448  $excludedDoktypes = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.excludeDoktypes');
449  if (!empty($excludedDoktypes)) {
450  $queryBuilder->andWhere(
451  $expressionBuilder->notIn(
452  'doktype',
453  $queryBuilder->createNamedParameter(
454  GeneralUtility::intExplode(',', $excludedDoktypes, true),
455  Connection::PARAM_INT_ARRAY
456  )
457  )
458  );
459  }
460 
461  if ($searchFilter !== '') {
462  $searchParts = $expressionBuilder->orX();
463  if (is_numeric($searchFilter) && $searchFilter > 0) {
464  $searchParts->add(
465  $expressionBuilder->eq('uid', $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_INT))
466  );
467  }
468  $searchFilter = '%' . $queryBuilder->escapeLikeWildcards($searchFilter) . '%';
469  $useNavTitle = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showNavTitle');
470  $useAlias = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.searchInAlias');
471 
472  $aliasExpression = '';
473  if ($useAlias) {
474  $aliasExpression = $expressionBuilder->like(
475  'alias',
476  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
477  );
478  }
479 
480  if ($useNavTitle) {
481  $searchWhereAlias = $expressionBuilder->orX(
482  $expressionBuilder->like(
483  'nav_title',
484  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
485  ),
486  $expressionBuilder->andX(
487  $expressionBuilder->eq(
488  'nav_title',
489  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
490  ),
491  $expressionBuilder->like(
492  'title',
493  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
494  )
495  )
496  );
497  if (strlen($aliasExpression)) {
498  $searchWhereAlias->add($aliasExpression);
499  }
500  $searchParts->add($searchWhereAlias);
501  } else {
502  $searchParts->add(
503  $expressionBuilder->like(
504  'title',
505  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
506  )
507  );
508 
509  if (strlen($aliasExpression)) {
510  $searchParts->add($aliasExpression);
511  }
512  }
513 
514  $queryBuilder->andWhere($searchParts);
515  }
516  return $queryBuilder;
517  }
518 
526  protected function getSubpages($id, $searchFilter = '')
527  {
528  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
529  $queryBuilder->getRestrictions()
530  ->removeAll()
531  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
532  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
533  $result = [];
534  $queryBuilder = $this->setWhereClause($queryBuilder, $id, $searchFilter);
535  $queryResult = $queryBuilder->select('uid', 't3ver_wsid')
536  ->from('pages')
537  ->orderBy('sorting')
538  ->execute();
539  while ($row = $queryResult->fetch()) {
540  $result[$row['uid']] = $row;
541  }
542  return $result;
543  }
544 
551  protected function hasNodeSubPages($id)
552  {
553  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
554  $queryBuilder->getRestrictions()
555  ->removeAll()
556  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
557  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
558  $queryBuilder = $this->setWhereClause($queryBuilder, $id);
559  $count = $queryBuilder->count('uid')
560  ->from('pages')
561  ->execute()
562  ->fetchColumn(0);
563  return (bool)$count;
564  }
565 }
static getRecordWSOL( $table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
getRecordWithWorkspaceOverlay($uid, $unsetMovePointers=false)
setWhereClause(QueryBuilder $queryBuilder, $id, $searchFilter='')
getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node)
static getNodeRecord($nodeId, $unsetMovePointers=true)
Definition: Commands.php:272
createNamedParameter($value, int $type=\PDO::PARAM_STR, string $placeHolder=null)
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
static stripLogicalOperatorPrefix(string $constraint)
static getLiveVersionOfRecord($table, $uid, $fields=' *')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']