TYPO3  7.6
Tree/Pagetree/DataProvider.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Tree\Pagetree;
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 
19 
24 {
30  protected $nodeLimit = 0;
31 
37  protected $nodeCounter = 0;
38 
44  protected $showRootlineAboveMounts = false;
45 
51  protected $hiddenRecords = array();
52 
58  protected $processCollectionHookObjects = array();
59 
65  public function __construct($nodeLimit = null)
66  {
67  if ($nodeLimit === null) {
68  $nodeLimit = $GLOBALS['TYPO3_CONF_VARS']['BE']['pageTree']['preloadLimit'];
69  }
70  $this->nodeLimit = abs((int)$nodeLimit);
71 
72  $this->showRootlineAboveMounts = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showPathAboveMounts');
73 
74  $this->hiddenRecords = GeneralUtility::trimExplode(',', $GLOBALS['BE_USER']->getTSConfigVal('options.hideRecords.pages'));
75  $hookElements = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/tree/pagetree/class.t3lib_tree_pagetree_dataprovider.php']['postProcessCollections'];
76  if (is_array($hookElements)) {
77  foreach ($hookElements as $classRef) {
79  $hookObject = GeneralUtility::getUserObj($classRef);
80  if ($hookObject instanceof \TYPO3\CMS\Backend\Tree\Pagetree\CollectionProcessorInterface) {
81  $this->processCollectionHookObjects[] = $hookObject;
82  }
83  }
84  }
85  }
86 
92  public function getRoot()
93  {
95  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode::class);
96  $node->setId('root');
97  $node->setExpanded(true);
98  return $node;
99  }
100 
109  public function getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node, $mountPoint = 0, $level = 0)
110  {
112  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
113  if ($level >= 99) {
114  return $nodeCollection;
115  }
116  $isVirtualRootNode = false;
117  $subpages = $this->getSubpages($node->getId());
118  // check if fetching subpages the "root"-page
119  // and in case of a virtual root return the mountpoints as virtual "subpages"
120  if ((int)$node->getId() === 0) {
121  // check no temporary mountpoint is used
122  if (!(int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint']) {
123  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
124  $mountPoints = array_unique($mountPoints);
125  if (!in_array(0, $mountPoints)) {
126  // using a virtual root node
127  // so then return the mount points here as "subpages" of the first node
128  $isVirtualRootNode = true;
129  $subpages = array();
130  foreach ($mountPoints as $webMountPoint) {
131  $subpages[] = array(
132  'uid' => $webMountPoint,
133  'isMountPoint' => true
134  );
135  }
136  }
137  }
138  }
139  if (is_array($subpages) && !empty($subpages)) {
140  foreach ($subpages as $subpage) {
141  if (in_array($subpage['uid'], $this->hiddenRecords)) {
142  continue;
143  }
144  // must be calculated above getRecordWithWorkspaceOverlay,
145  // because the information is lost otherwise
146  $isMountPoint = $subpage['isMountPoint'] === true;
147  if ($isVirtualRootNode) {
148  $mountPoint = (int)$subpage['uid'];
149  }
150  $subpage = $this->getRecordWithWorkspaceOverlay($subpage['uid'], true);
151  if (!$subpage) {
152  continue;
153  }
154  $subNode = Commands::getNewNode($subpage, $mountPoint);
155  $subNode->setIsMountPoint($isMountPoint);
156  if ($isMountPoint && $this->showRootlineAboveMounts) {
157  $rootline = Commands::getMountPointPath($subpage['uid']);
158  $subNode->setReadableRootline($rootline);
159  }
160  if ($this->nodeCounter < $this->nodeLimit) {
161  $childNodes = $this->getNodes($subNode, $mountPoint, $level + 1);
162  $subNode->setChildNodes($childNodes);
163  $this->nodeCounter += $childNodes->count();
164  } else {
165  $subNode->setLeaf(!$this->hasNodeSubPages($subNode->getId()));
166  }
167  if (!$GLOBALS['BE_USER']->isAdmin() && (int)$subpage['editlock'] === 1) {
168  $subNode->setLabelIsEditable(false);
169  }
170  $nodeCollection->append($subNode);
171  }
172  }
173  foreach ($this->processCollectionHookObjects as $hookObject) {
175  $hookObject->postProcessGetNodes($node, $mountPoint, $level, $nodeCollection);
176  }
177  return $nodeCollection;
178  }
179 
187  protected function getRecordWithWorkspaceOverlay($uid, $unsetMovePointers = false)
188  {
189  return BackendUtility::getRecordWSOL('pages', $uid, '*', '', true, $unsetMovePointers);
190  }
191 
200  public function getFilteredNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node, $searchFilter, $mountPoint = 0)
201  {
203  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
204  $records = $this->getSubpages(-1, $searchFilter);
205  if (!is_array($records) || empty($records)) {
206  return $nodeCollection;
207  } elseif (count($records) > 500) {
208  return $nodeCollection;
209  }
210  // check no temporary mountpoint is used
211  $mountPoints = (int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
212  if (!$mountPoints) {
213  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
214  $mountPoints = array_unique($mountPoints);
215  } else {
216  $mountPoints = array($mountPoints);
217  }
218  $isNumericSearchFilter = is_numeric($searchFilter) && $searchFilter > 0;
219  $searchFilterQuoted = preg_quote($searchFilter, '/');
220  $nodeId = (int)$node->getId();
221  $processedRecordIds = array();
222  foreach ($records as $record) {
223  if ((int)$record['t3ver_wsid'] !== (int)$GLOBALS['BE_USER']->workspace && (int)$record['t3ver_wsid'] !== 0) {
224  continue;
225  }
226  $liveVersion = BackendUtility::getLiveVersionOfRecord('pages', $record['uid'], 'uid');
227  if ($liveVersion !== null) {
228  $record = $liveVersion;
229  }
230 
231  $record = Commands::getNodeRecord($record['uid'], false);
232  if ((int)$record['pid'] === -1
233  || in_array($record['uid'], $this->hiddenRecords)
234  || in_array($record['uid'], $processedRecordIds)
235  ) {
236  continue;
237  }
238  $processedRecordIds[] = $record['uid'];
239 
240  $rootline = BackendUtility::BEgetRootLine($record['uid'], '', $GLOBALS['BE_USER']->workspace != 0);
241  $rootline = array_reverse($rootline);
242  if (!in_array(0, $mountPoints, true)) {
243  $isInsideMountPoints = false;
244  foreach ($rootline as $rootlineElement) {
245  if (in_array((int)$rootlineElement['uid'], $mountPoints, true)) {
246  $isInsideMountPoints = true;
247  break;
248  }
249  }
250  if (!$isInsideMountPoints) {
251  continue;
252  }
253  }
254  $reference = $nodeCollection;
255  $inFilteredRootline = false;
256  $amountOfRootlineElements = count($rootline);
257  for ($i = 0; $i < $amountOfRootlineElements; ++$i) {
258  $rootlineElement = $rootline[$i];
259  $rootlineElement['uid'] = (int)$rootlineElement['uid'];
260  $isInWebMount = (int)$GLOBALS['BE_USER']->isInWebMount($rootlineElement['uid']);
261  if (!$isInWebMount
262  || ($rootlineElement['uid'] === (int)$mountPoints[0]
263  && $rootlineElement['uid'] !== $isInWebMount)
264  ) {
265  continue;
266  }
267  if ((int)$rootlineElement['pid'] === $nodeId
268  || $rootlineElement['uid'] === $nodeId
269  || ($rootlineElement['uid'] === $isInWebMount
270  && in_array($rootlineElement['uid'], $mountPoints, true))
271  ) {
272  $inFilteredRootline = true;
273  }
274  if (!$inFilteredRootline || $rootlineElement['uid'] === $mountPoint) {
275  continue;
276  }
277  $rootlineElement = Commands::getNodeRecord($rootlineElement['uid'], false);
278  $ident = (int)$rootlineElement['sorting'] . (int)$rootlineElement['uid'];
279  if ($reference && $reference->offsetExists($ident)) {
281  $refNode = $reference->offsetGet($ident);
282  $refNode->setExpanded(true);
283  $refNode->setLeaf(false);
284  $reference = $refNode->getChildNodes();
285  if ($reference == null) {
286  $reference = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
287  $refNode->setChildNodes($reference);
288  }
289  } else {
290  $refNode = Commands::getNewNode($rootlineElement, $mountPoint);
291  $replacement = '<span class="typo3-pagetree-filteringTree-highlight">$1</span>';
292  if ($isNumericSearchFilter && (int)$rootlineElement['uid'] === (int)$searchFilter) {
293  $text = str_replace('$1', $refNode->getText(), $replacement);
294  } else {
295  $text = preg_replace('/(' . $searchFilterQuoted . ')/i', $replacement, $refNode->getText());
296  }
297  $refNode->setText($text, $refNode->getTextSourceField(), $refNode->getPrefix(), $refNode->getSuffix());
299  $childCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
300  if ($i + 1 >= $amountOfRootlineElements) {
301  $childNodes = $this->getNodes($refNode, $mountPoint);
302  foreach ($childNodes as $childNode) {
304  $childRecord = $childNode->getRecord();
305  $childIdent = (int)$childRecord['sorting'] . (int)$childRecord['uid'];
306  $childCollection->offsetSet($childIdent, $childNode);
307  }
308  $refNode->setChildNodes($childNodes);
309  }
310  $refNode->setChildNodes($childCollection);
311  $reference->offsetSet($ident, $refNode);
312  $reference->ksort();
313  $reference = $childCollection;
314  }
315  }
316  }
317  foreach ($this->processCollectionHookObjects as $hookObject) {
319  $hookObject->postProcessFilteredNodes($node, $searchFilter, $mountPoint, $nodeCollection);
320  }
321  return $nodeCollection;
322  }
323 
332  public function getTreeMounts($searchFilter = '')
333  {
335  $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class);
336  $isTemporaryMountPoint = false;
337  $rootNodeIsVirtual = false;
338  $mountPoints = (int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
339  if (!$mountPoints) {
340  $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
341  $mountPoints = array_unique($mountPoints);
342  if (!in_array(0, $mountPoints)) {
343  $rootNodeIsVirtual = true;
344  // use a virtual root
345  // the real mountpoints will be fetched in getNodes() then
346  // since those will be the "subpages" of the virtual root
347  $mountPoints = array(0);
348  }
349  } else {
350  $isTemporaryMountPoint = true;
351  $mountPoints = array($mountPoints);
352  }
353  if (empty($mountPoints)) {
354  return $nodeCollection;
355  }
356 
357  foreach ($mountPoints as $mountPoint) {
358  if ($mountPoint === 0) {
359  $sitename = 'TYPO3';
360  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] !== '') {
361  $sitename = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
362  }
363  $record = array(
364  'uid' => 0,
365  'title' => $sitename
366  );
367  $subNode = Commands::getNewNode($record);
368  $subNode->setLabelIsEditable(false);
369  if ($rootNodeIsVirtual) {
370  $subNode->setType('virtual_root');
371  $subNode->setIsDropTarget(false);
372  } else {
373  $subNode->setType('pages_root');
374  $subNode->setIsDropTarget(true);
375  }
376  } else {
377  if (in_array($mountPoint, $this->hiddenRecords)) {
378  continue;
379  }
380  $record = $this->getRecordWithWorkspaceOverlay($mountPoint);
381  if (!$record) {
382  continue;
383  }
384  $subNode = Commands::getNewNode($record, $mountPoint);
385  if ($this->showRootlineAboveMounts && !$isTemporaryMountPoint) {
386  $rootline = Commands::getMountPointPath($record['uid']);
387  $subNode->setReadableRootline($rootline);
388  }
389  }
390  if (count($mountPoints) <= 1) {
391  $subNode->setExpanded(true);
392  $subNode->setCls('typo3-pagetree-node-notExpandable');
393  }
394  $subNode->setIsMountPoint(true);
395  $subNode->setDraggable(false);
396  if ($searchFilter === '') {
397  $childNodes = $this->getNodes($subNode, $mountPoint);
398  } else {
399  $childNodes = $this->getFilteredNodes($subNode, $searchFilter, $mountPoint);
400  $subNode->setExpanded(true);
401  }
402  $subNode->setChildNodes($childNodes);
403  $nodeCollection->append($subNode);
404  }
405  foreach ($this->processCollectionHookObjects as $hookObject) {
407  $hookObject->postProcessGetTreeMounts($searchFilter, $nodeCollection);
408  }
409  return $nodeCollection;
410  }
411 
419  protected function getWhereClause($id, $searchFilter = '')
420  {
421  $where = $GLOBALS['BE_USER']->getPagePermsClause(1) . BackendUtility::deleteClause('pages') . BackendUtility::versioningPlaceholderClause('pages');
422  if (is_numeric($id) && $id >= 0) {
423  $where .= ' AND pid= ' . $GLOBALS['TYPO3_DB']->fullQuoteStr((int)$id, 'pages');
424  }
425 
426  $excludedDoktypes = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.excludeDoktypes');
427  if (!empty($excludedDoktypes)) {
428  $excludedDoktypes = $GLOBALS['TYPO3_DB']->fullQuoteArray(GeneralUtility::intExplode(',', $excludedDoktypes), 'pages');
429  $where .= ' AND doktype NOT IN (' . implode(',', $excludedDoktypes) . ')';
430  }
431 
432  if ($searchFilter !== '') {
433  if (is_numeric($searchFilter) && $searchFilter > 0) {
434  $searchWhere .= 'uid = ' . (int)$searchFilter . ' OR ';
435  }
436  $searchFilter = $GLOBALS['TYPO3_DB']->fullQuoteStr('%' . $searchFilter . '%', 'pages');
437  $useNavTitle = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showNavTitle');
438  $useAlias = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.searchInAlias');
439 
440  $searchWhereAlias = '';
441  if ($useAlias) {
442  $searchWhereAlias = ' OR alias LIKE ' . $searchFilter;
443  }
444 
445  if ($useNavTitle) {
446  $searchWhere .= '(nav_title LIKE ' . $searchFilter .
447  ' OR (nav_title = "" AND title LIKE ' . $searchFilter . ')' . $searchWhereAlias . ')';
448  } else {
449  $searchWhere .= 'title LIKE ' . $searchFilter . $searchWhereAlias;
450  }
451 
452  $where .= ' AND (' . $searchWhere . ')';
453  }
454  return $where;
455  }
456 
464  protected function getSubpages($id, $searchFilter = '')
465  {
466  $where = $this->getWhereClause($id, $searchFilter);
467  return $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,t3ver_wsid', 'pages', $where, '', 'sorting', '', 'uid');
468  }
469 
476  protected function hasNodeSubPages($id)
477  {
478  $where = $this->getWhereClause($id);
479  $subpage = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', 'pages', $where, '', 'sorting', '', 'uid');
480  $returnValue = true;
481  if (!$subpage['uid']) {
482  $returnValue = false;
483  }
484  return $returnValue;
485  }
486 }