150 public $fieldArray = [
'uid',
'pid',
'title',
'is_siteroot'];
158 public $defaultList =
'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id';
299 if ($routePath = GeneralUtility::_GP(
'route')) {
300 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
301 $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath);
303 $this->thisScript = GeneralUtility::getIndpEnv(
'SCRIPT_NAME');
312 return strpos($this->thisScript,
'?') ===
false ? $this->thisScript .
'?' : $this->thisScript .
'&';
332 if (!is_array($this->MOUNTS)) {
334 $this->MOUNTS = [0 => 0];
337 $this->treeName = str_replace(
'_',
'', $this->treeName ?: $this->table);
342 $this->dataLookup =
false;
351 public function addField($field, $noCheck =
false)
353 if ($noCheck || is_array(
$GLOBALS[
'TCA'][$this->table][
'columns'][$field]) || GeneralUtility::inList($this->defaultList, $field)) {
354 $this->fieldArray[] = $field;
366 $this->ids_hierarchy = [];
367 $this->orig_ids_hierarchy = [];
386 $lastMountPointPid = 0;
389 foreach ($this->MOUNTS as $idx => $uid) {
396 $this->ids = $curIds;
398 $cmd = $this->bank .
'_' . ($isOpen ?
'0_' :
'1_') . $uid .
'_' . $this->treeName;
400 $firstHtml = $this->
PM_ATagWrap(
'', $cmd,
'', $isOpen);
404 if (is_array($rootRec)) {
405 $firstHtml .= $this->
getIcon($rootRec);
408 if ($this->ext_showPathAboveMounts) {
409 $mountPointPid = $rootRec[
'pid'];
410 if ($lastMountPointPid !== $mountPointPid) {
412 $this->tree[] = [
'isMountPointPath' =>
true,
'title' =>
$title];
414 $lastMountPointPid = $mountPointPid;
421 if (is_array($rootRec)) {
423 $uid = $rootRec[
'uid'];
425 $this->tree[] = [
'HTML' => $firstHtml,
'row' => $rootRec,
'hasSub' => $isOpen,
'bank' =>
$this->bank];
428 $depthData =
'<span class="treeline-icon treeline-icon-clear"></span>';
429 if ($this->addSelfId) {
432 $this->
getTree($uid, 999, $depthData);
435 $treeArr = array_merge($treeArr, $this->tree);
449 $titleLen = (int)$this->BE_USER->uc[
'titleLen'];
450 if (!is_array($treeArr)) {
455 foreach ($treeArr as $treeItem) {
457 if ($treeItem[
'isFirst']) {
458 $out .=
'<ul class="list-tree">';
462 if ($treeItem[
'hasSub']) {
463 $classAttr .=
' list-tree-control-open';
466 $idAttr = htmlspecialchars($this->domIdPrefix . $this->
getId($treeItem[
'row']) .
'_' . $treeItem[
'bank']);
468 <li id="' . $idAttr .
'"' . ($classAttr ?
' class="' . trim($classAttr) .
'"' :
'') .
'>
469 <span class="list-tree-group">
470 <span class="list-tree-icon">' . $treeItem[
'HTML'] .
'</span>
471 <span class="list-tree-title">' . $this->
wrapTitle($this->
getTitleStr($treeItem[
'row'], $titleLen), $treeItem[
'row'], $treeItem[
'bank']) .
'</span>
474 if (!$treeItem[
'hasSub']) {
480 if ($treeItem[
'isLast']) {
481 $closeDepth[$treeItem[
'invertedDepth']] = 1;
485 if ($treeItem[
'isLast'] && !$treeItem[
'hasSub']) {
486 for ($i = $treeItem[
'invertedDepth']; $closeDepth[$i] == 1; $i++) {
488 $out .=
'</ul></li>';
492 $out =
'<ul class="list-tree list-tree-root list-tree-root-clean">' . $out .
'</ul>';
513 public function PMicon($row, $a, $c, $nextCount, $isOpen)
516 $cmd = $this->bank .
'_' . ($isOpen ?
'0_' :
'1_') . $row[
'uid'] .
'_' . $this->treeName;
517 $bMark = $this->bank .
'_' . $row[
'uid'];
533 public function PM_ATagWrap($icon, $cmd, $bMark =
'', $isOpen =
false)
535 if ($this->thisScript) {
536 $anchor = $bMark ?
'#' . $bMark :
'';
537 $name = $bMark ?
' name="' . $bMark .
'"' :
'';
539 return '<a class="list-tree-control ' . ($isOpen ?
'list-tree-control-open' :
'list-tree-control-closed') .
'" href="' . htmlspecialchars($aUrl) .
'"' . $name .
'><i class="fa"></i></a>';
555 $aOnClick =
'return jumpTo(' . GeneralUtility::quoteJSvalue($this->
getJumpToParam($row)) .
',this,' . GeneralUtility::quoteJSvalue($this->domIdPrefix . $this->
getId($row)) .
',' .
$bank .
');';
556 return '<a href="#" onclick="' . htmlspecialchars($aOnClick) .
'">' .
$title .
'</a>';
581 return preg_replace(
'/ ?\\/?>$/',
'', $icon) .
' ' . $attr .
' />';
594 if ($row[
'php_tree_stop']) {
595 $str .=
'<a href="' . htmlspecialchars(GeneralUtility::linkThisScript([
'setTempDBmount' => $row[
'uid']])) .
'" class="text-danger">+</a> ';
628 $this->stored = unserialize($this->BE_USER->uc[
'browseTrees'][$this->treeName], [
'allowed_classes' =>
false]);
633 $PM = explode(
'_', GeneralUtility::_GP(
'PM'));
634 if (count($PM) === 4 && $PM[3] == $this->treeName) {
635 if (isset($this->MOUNTS[$PM[0]])) {
638 $this->stored[$PM[0]][$PM[2]] = 1;
641 unset($this->stored[$PM[0]][$PM[2]]);
656 $this->BE_USER->uc[
'browseTrees'][
$this->treeName] = serialize($this->stored);
657 $this->BE_USER->writeUC();
673 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
688 $title = $this->showDefaultTitleAttribute ? htmlspecialchars(
'UID: ' . $row[
'uid']) : $this->
getTitleAttrib($row);
689 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
690 $icon = $row[
'is_siteroot'] ? $iconFactory->getIcon(
'apps-pagetree-folder-root',
Icon::SIZE_SMALL) : $iconFactory->getIconForRecord($this->table, $row,
Icon::SIZE_SMALL);
691 $icon =
'<span title="' .
$title .
'">' . $icon->render() .
'</span>';
705 $title = htmlspecialchars(GeneralUtility::fixed_lgd_cs($row[
'title'], $titleLen));
706 $title = trim($row[
'title']) ===
'' ?
'<em>[' . htmlspecialchars($this->
getLanguageService()->sL(
'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')) .
']</em>' :
$title;
719 return htmlspecialchars($row[
'title']);
728 public function getId($row)
741 return $this->
getId($row);
757 public function getTree($uid, $depth = 999, $depthData =
'')
760 $this->buffer_idH = [];
762 $depth = (int)$depth;
767 $crazyRecursionLimiter = 9999;
770 while ($crazyRecursionLimiter > 0 && ($row = $this->
getDataNext($res))) {
771 if (!$this->
getBackendUser()->isInWebMount($this->table ===
'pages' ? $row : $row[
'pid'])) {
777 $crazyRecursionLimiter--;
778 $newID = $row[
'uid'];
780 throw new \RuntimeException(
'Endless recursion detected: TYPO3 has detected an error in the database. Please fix it manually (e.g. using phpMyAdmin) and change the UID of ' . $this->table .
':0 to a new value. See http://forge.typo3.org/issues/16150 to get more information about a possible cause.', 1294586383);
786 $treeKey = key($this->tree);
788 if ($this->setRecs) {
789 $this->recs[$row[
'uid']] = $row;
792 $this->ids[] = ($idH[$row[
'uid']][
'uid'] = $row[
'uid']);
793 $this->ids_hierarchy[$depth][] = $row[
'uid'];
794 $this->orig_ids_hierarchy[$depth][] = $row[
'_ORIG_uid'] ?: $row[
'uid'];
797 $nextLevelDepthData = $depthData .
'<span class="treeline-icon treeline-icon-' . ($a === $c ?
'clear' :
'line') .
'"></span>';
798 $hasSub = $this->
expandNext($newID) && !$row[
'php_tree_stop'];
799 if ($depth > 1 && $hasSub) {
800 $nextCount = $this->
getTree($newID, $depth - 1, $nextLevelDepthData);
801 if (!empty($this->buffer_idH)) {
812 if ($this->makeHTML) {
816 $this->tree[$treeKey] = [
819 'invertedDepth' => $depth,
820 'depthData' => $depthData,
822 'hasSub' => $nextCount && $hasSub,
823 'isFirst' => $a === 1,
824 'isLast' => $a === $c,
829 $this->buffer_idH = $idH;
848 if (is_array($this->data)) {
850 trigger_error(
'Handling array data in AbstractTreeView will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
854 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
855 $queryBuilder->getRestrictions()
857 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
858 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
859 $count = $queryBuilder
863 $queryBuilder->expr()->eq(
865 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
895 if (is_array($this->data)) {
897 return $this->dataLookup[$uid];
914 if (is_array($this->data)) {
916 if (!is_array($this->dataLookup[$parentId][$this->subLevelID])) {
919 reset($this->dataLookup[$parentId][$this->subLevelID]);
923 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
924 $queryBuilder->getRestrictions()
926 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
927 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
929 ->select(...$this->fieldArray)
932 $queryBuilder->expr()->eq(
934 $queryBuilder->createNamedParameter($parentId, \PDO::PARAM_INT)
940 list($fieldName, $order) = $orderPair;
941 $queryBuilder->addOrderBy($fieldName, $order);
944 return $queryBuilder->execute();
957 if (is_array($this->data)) {
959 return count($this->dataLookup[$res][$this->subLevelID]);
961 return $res->rowCount();
975 if (is_array($this->data)) {
980 $key = key($this->dataLookup[$res][$this->subLevelID]);
981 next($this->dataLookup[$res][$this->subLevelID]);
986 while ($row = $res->fetch()) {
988 if (is_array($row)) {
1004 if (!is_array($this->data)) {
1005 $res->closeCursor();
1023 if (!$this->setDataFromArrayDeprecationThrown) {
1025 $this->setDataFromArrayDeprecationThrown =
true;
1026 trigger_error(
'AbstractTreeView->setDataFromArray() will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
1031 $this->data = &$dataArr;
1032 $this->dataLookup = [];
1036 foreach ($dataArr as $uid => $val) {
1037 $dataArr[$uid][
'uid'] = $uid;
1038 $dataArr[$uid][
'pid'] = $pid;
1040 $this->dataLookup[$uid] = &$dataArr[$uid];
1041 if (is_array($val[$this->subLevelID])) {
1056 trigger_error(
'AbstractTreeView->setDataFromTreeArray() will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
1057 $this->data = &$treeArr;
1058 $this->dataLookup = &$treeLookupArr;
1073 array_shift($rootline);
1075 foreach ($rootline as $rootlineElement) {
1077 $text = $record[
'title'];
1078 if ((
bool)($this->
getBackendUser()->getTSConfig()[
'options.'][
'pageTree.'][
'showNavTitle'] ??
false)
1079 && trim($record[
'nav_title'] ??
'') !==
''
1081 $text = $record[
'nav_title'];
1083 $path[] = htmlspecialchars($text);
1085 return '/' . implode(
'/', $path);