Beispiel #1
0
    /**
     * Creates the version selector for the page id inputted.
     * Moved out of the core file \TYPO3\CMS\Backend\Template\DocumentTemplate
     *
     * @param int $id Page id to create selector for.
     * @param bool $noAction If set, there will be no button for swapping page.
     * @return void
     * @see \TYPO3\CMS\Backend\Template\DocumentTemplate
     */
    public function getVersionSelector($id, $noAction = FALSE)
    {
        if ($id <= 0) {
            return;
        }
        if ($GLOBALS['BE_USER']->workspace == 0) {
            // Get Current page record:
            $curPage = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $id);
            // If the selected page is not online, find the right ID
            $onlineId = $curPage['pid'] == -1 ? $curPage['t3ver_oid'] : $id;
            // Select all versions of online version:
            $versions = \TYPO3\CMS\Backend\Utility\BackendUtility::selectVersionsOfRecord('pages', $onlineId, 'uid,pid,t3ver_label,t3ver_oid,t3ver_wsid,t3ver_id');
            // If more than one was found...:
            if (count($versions) > 1) {
                $selectorLabel = '<strong>' . $GLOBALS['LANG']->sL('LLL:EXT:version/locallang.xlf:versionSelect.label', TRUE) . '</strong>';
                // Create selector box entries:
                $opt = array();
                foreach ($versions as $vRow) {
                    if ($vRow['uid'] == $onlineId) {
                        // Live version
                        $label = '[' . $GLOBALS['LANG']->sL('LLL:EXT:version/locallang.xlf:versionSelect.live', TRUE) . ']';
                    } else {
                        $label = $vRow['t3ver_label'] . ' (' . $GLOBALS['LANG']->sL('LLL:EXT:version/locallang.xlf:versionId', TRUE) . ' ' . $vRow['t3ver_id'] . ($vRow['t3ver_wsid'] != 0 ? ' ' . $GLOBALS['LANG']->sL('LLL:EXT:version/locallang.xlf:workspaceId', TRUE) . ' ' . $vRow['t3ver_wsid'] : '') . ')';
                    }
                    $opt[] = '<option value="' . htmlspecialchars(GeneralUtility::linkThisScript(array('id' => $vRow['uid']))) . '"' . ($id == $vRow['uid'] ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
                }
                // Add management link:
                $management = '<input type="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.mgm', TRUE) . '" onclick="window.location.href=\'' . htmlspecialchars($GLOBALS['BACK_PATH'] . \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl('web_txversionM1', array('table' => 'pages', 'uid' => $onlineId))) . '\';" />';
                // Create onchange handler:
                $onChange = 'window.location.href=this.options[this.selectedIndex].value;';
                // Controls:
                if ($id == $onlineId) {
                    $controls = '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/blinkarrow_left.gif', 'width="5" height="9"') . ' class="absmiddle" alt="" /> <strong>' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.online', TRUE) . '</strong>';
                } elseif (!$noAction) {
                    $href = $GLOBALS['TBE_TEMPLATE']->issueCommand('&cmd[pages][' . $onlineId . '][version][swapWith]=' . $id . '&cmd[pages][' . $onlineId . '][version][action]=swap', GeneralUtility::linkThisScript(array('id' => $onlineId)));
                    $controls = '<a href="' . htmlspecialchars($href) . '" class="text-nowrap">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-version-swap-version', array('title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.swapPage', TRUE), 'style' => 'margin-left:5px;vertical-align:bottom;')) . '<strong>' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.swap', TRUE) . '</strong></a>';
                }
                // Write out HTML code:
                return '
					<!--
						Version selector:
					-->
					<table border="0" cellpadding="0" cellspacing="0" id="typo3-versionSelector">
						<tr>
							<td>' . $selectorLabel . '</td>
							<td>
								<select onchange="' . htmlspecialchars($onChange) . '">
									' . implode('', $opt) . '
								</select></td>
							<td>' . $controls . '</td>
							<td>' . $management . '</td>
						</tr>
					</table>
				';
            }
        }
    }
    /**
     * Creates the control panel for a single record in the listing.
     *
     * @param string $table The table
     * @param array $row The record for which to make the control panel.
     *
     * @return string HTML table with the control panel (unless disabled)
     * @throws UnexpectedValueException If hook was of wrong interface
     */
    public function makeControl($table, array $row)
    {
        $backendUser = $this->getBackendUser();
        $language = $this->getLanguageService();
        if ($this->dontShowClipControlPanels) {
            return '';
        }
        $rowUid = $row['uid'];
        if (ExtensionManagementUtility::isLoaded('version') && isset($row['_ORIG_uid'])) {
            $rowUid = $row['_ORIG_uid'];
        }
        $cells = array();
        // If the listed table is 'pages' we have to request
        // the permission settings for each page:
        $localCalcPerms = 0;
        if ($table == 'tx_commerce_categories' || $table == 'tx_commerce_products') {
            /**
             * Utility
             *
             * @var \CommerceTeam\Commerce\Utility\BackendUserUtility $utility
             */
            $utility = GeneralUtility::makeInstance('CommerceTeam\\Commerce\\Utility\\BackendUserUtility');
            $localCalcPerms = $utility->calcPerms((array) BackendUtility::getRecord('tx_commerce_categories', $this->parentUid));
        }
        // This expresses the edit permissions for this particular element:
        $permsEdit = $table == 'tx_commerce_categories' && $localCalcPerms & 2 || $table != 'tx_commerce_categories' && $this->calcPerms & 16;
        // "Show" link (only tx_commerce_categories and tx_commerce_products elements)
        if ($table == 'tx_commerce_categories' || $table == 'tx_commerce_products') {
            $cells['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($table === 'tx_commerce_products' ? $this->id : $row['uid'], $this->backPath, '', $table === 'tx_commerce_products' ? '#' . $row['uid'] : '')) . '" title="' . $language->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
        } elseif (!$this->table) {
            $cells['view'] = $this->spaceIcon;
        }
        // "Edit" link: ( Only if permissions to edit the page-record of
        // the content of the parent page ($this->id)
        if ($permsEdit) {
            $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
            $cells['edit'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $language->getLL('edit', TRUE) . '">' . ($GLOBALS['TCA'][$table]['ctrl']['readOnly'] ? IconUtility::getSpriteIcon('actions-document-open-read-only') : IconUtility::getSpriteIcon('actions-document-open')) . '</a>';
        } elseif (!$this->table) {
            $cells['edit'] = $this->spaceIcon;
        }
        // "Move" wizard link for tx_commerce_categories/tx_commerce_products elements:
        if ($table == 'tx_commerce_products' && $permsEdit || $table == 'tx_commerce_categories') {
            $options = array('title' => $language->getLL('move_' . ($table == 'tx_commerce_products' ? 'record' : 'page'), TRUE));
            $cells['move'] = '<a href="#" onclick="' . htmlspecialchars('return jumpExt(\'' . $this->backPath . 'move_el.php?table=' . $table . '&uid=' . $row['uid'] . '\');') . '">' . ($table == 'tx_commerce_products' ? IconUtility::getSpriteIcon('actions-document-move', $options) : IconUtility::getSpriteIcon('actions-page-move', $options)) . '</a>';
        } elseif (!$this->table) {
            $cells['move'] = $this->spaceIcon;
        }
        // If the extended control panel is enabled OR if we are seeing a single table:
        if ($GLOBALS['SOBE']->MOD_SETTINGS['bigControlPanel'] || $this->table) {
            // "Info": (All records)
            $cells['viewBig'] = '<a href="#" onclick="' . htmlspecialchars('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;') . '" title="' . $language->getLL('showInfo', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-info') . '</a>';
            // If the table is NOT a read-only table, then show these links:
            if (!$GLOBALS['TCA'][$table]['ctrl']['readOnly']) {
                // "Revert" link (history/undo)
                $cells['history'] = '<a href="#" onclick="' . htmlspecialchars('return jumpExt(\'' . $this->backPath . 'show_rechis.php?element=' . rawurlencode($table . ':' . $row['uid']) . '\',\'#latest\');') . '" title="' . $language->getLL('history', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-history-open') . '</a>';
                // Versioning:
                if (ExtensionManagementUtility::isLoaded('version') && !ExtensionManagementUtility::isLoaded('workspaces')) {
                    $vers = BackendUtility::selectVersionsOfRecord($table, $row['uid'], 'uid', $this->getBackendUser()->workspace, FALSE, $row);
                    // If table can be versionized.
                    if (is_array($vers)) {
                        $versionIcon = 'no-version';
                        if (count($vers) > 1) {
                            $versionIcon = count($vers) - 1;
                        }
                        $cells['version'] = '<a href="' . htmlspecialchars($this->backPath . ExtensionManagementUtility::extRelPath('version') . 'cm1/index.php?table=' . rawurlencode($table) . '&uid=' . rawurlencode($row['uid'])) . '" title="' . $language->getLL('displayVersions', TRUE) . '">' . IconUtility::getSpriteIcon('status-version-' . $versionIcon) . '</a>';
                    } elseif (!$this->table) {
                        $cells['version'] = $this->spaceIcon;
                    }
                }
                // "Edit Perms" link:
                if ($table == 'tx_commerce_categories' && $backendUser->check('modules', 'txcommerceM1_permission')) {
                    $cells['perms'] = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('txcommerceM1_permission') . '&control[tx_commerce_categories][uid]=' . $row['uid'] . '&return_id=' . $row['uid'] . '&edit=1') . '">' . IconUtility::getSpriteIcon('status-status-locked', array('titel' => $language->getLL('permissions', TRUE))) . '</a>';
                } elseif (!$this->table && $backendUser->check('modules', 'web_perm')) {
                    $cells['perms'] = $this->spaceIcon;
                }
                // "New record after" link (ONLY if the records in the table are sorted
                // by a "sortby"-row or if default values can depend on previous record):
                if ($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
                    if ($table != 'tx_commerce_categories' && $this->calcPerms & 16 || $table == 'tx_commerce_categories' && $this->calcPerms & 8) {
                        if ($this->showNewRecLink($table) && $this->parentUid) {
                            $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
                            $options = array('title' => $language->getLL('new' . ($table == 'tx_commerce_categories' ? 'Category' : 'Record'), TRUE));
                            $cells['new'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, $this->backPath, -1)) . '"' . ($table == 'tx_commerce_categories' ? IconUtility::getSpriteIcon('actions-page-new', $options) : IconUtility::getSpriteIcon('actions-document-new', $options)) . '</a>';
                        }
                    }
                } elseif (!$this->table) {
                    $cells['new'] = $this->spaceIcon;
                }
                // "Up/Down" links
                if ($permsEdit && $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
                    // Up
                    if (isset($this->currentTable['prev'][$row['uid']])) {
                        $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
                        $cells['moveUp'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('moveUp', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-up') . '</a>';
                    } else {
                        $cells['moveUp'] = $this->spaceIcon;
                    }
                    // Down
                    if ($this->currentTable['next'][$row['uid']]) {
                        $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
                        $cells['moveDown'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('moveDown', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-down') . '</a>';
                    } else {
                        $cells['moveDown'] = $this->spaceIcon;
                    }
                } elseif (!$this->table) {
                    $cells['moveUp'] = $this->spaceIcon;
                    $cells['moveDown'] = $this->spaceIcon;
                }
                // "Hide/Unhide" links:
                $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
                if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] || $backendUser->check('non_exclude_fields', $table . ':' . $hiddenField))) {
                    if ($row[$hiddenField]) {
                        $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
                        $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('unHide' . ($table == 'tx_commerce_categories' ? 'Category' : ''), TRUE) . '">' . IconUtility::getSpriteIcon('actions-edit-unhide') . '</a>';
                    } else {
                        $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
                        $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('hide' . ($table == 'tx_commerce_categories' ? 'Category' : ''), TRUE) . '">' . IconUtility::getSpriteIcon('actions-edit-hide') . '</a>';
                    }
                } elseif (!$this->table) {
                    $cells['hide'] = $this->spaceIcon;
                }
                // "Delete" link:
                if ($table == 'tx_commerce_categories' && $localCalcPerms & 4 || $table != 'tx_commerce_categories' && $this->calcPerms & 16) {
                    $titleOrig = BackendUtility::getRecordTitle($table, $row, FALSE, TRUE);
                    $title = GeneralUtility::slashJS(GeneralUtility::fixed_lgd_cs($titleOrig, $this->fixedL), 1);
                    $params = '&cmd[' . $table . '][' . $row['uid'] . '][delete]=1';
                    $refCountMsg = BackendUtility::referenceCount($table, $row['uid'], ' ' . $language->sL('LLL:EXT:lang/locallang_core.xml:labels.referencesToRecord'), $this->getReferenceCount($table, $row['uid'])) . BackendUtility::translationCount($table, $row['uid'], ' ' . $language->sL('LLL:EXT:lang/locallang_core.xml:labels.translationsOfRecord'));
                    $cells['delete'] = '<a href="#" onclick="' . htmlspecialchars('if (confirm(' . $language->JScharCode($language->getLL('deleteWarning') . ' "' . $title . '" ' . $refCountMsg) . ')) {jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');} return false;') . '">' . IconUtility::getSpriteIcon('actions-edit-delete', array('title' => $language->getLL('delete', TRUE))) . '</a>';
                } elseif (!$this->table) {
                    $cells['delete'] = $this->spaceIcon;
                }
                // "Levels" links: Moving pages into new levels...
                // @todo make moving left and right working with custom wizard
                if ($permsEdit && $table == 'pages' && !$this->searchLevels) {
                    // Up (Paste as the page right after the current parent page)
                    if ($this->calcPerms & 8) {
                        $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . -$this->id;
                        $cells['moveLeft'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('prevLevel', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-left') . '</a>';
                    }
                    // Down (Paste as subpage to the page right above)
                    if ($this->currentTable['prevUid'][$row['uid']]) {
                        $localCalcPerms = $backendUser->calcPerms(BackendUtility::getRecord('tx_commerce_categories', $this->currentTable['prevUid'][$row['uid']]));
                        if ($localCalcPerms & 8) {
                            $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
                            $cells['moveRight'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $language->getLL('nextLevel', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-right') . '</a>';
                        } else {
                            $cells['moveRight'] = $this->spaceIcon;
                        }
                    } else {
                        $cells['moveRight'] = $this->spaceIcon;
                    }
                } elseif (!$this->table) {
                    $cells['moveLeft'] = $this->spaceIcon;
                    $cells['moveRight'] = $this->spaceIcon;
                }
            }
        }
        /**
         * Record stat info hooks: Allows to insert HTML
         * 	before record icons on various places
         * @date 2007-09-22
         * @request Kasper Skårhøj <*****@*****.**>
         */
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
            $stat = '';
            $parameter = array($table, $row['uid']);
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $functionReference) {
                $stat .= GeneralUtility::callUserFunction($functionReference, $parameter, $this);
            }
            $cells['stat'] = $stat;
        }
        /**
         * Make control Hook: Allows to change control icons of records in list-module
         * @date 2007-11-20
         * @request Bernhard Kraft  <*****@*****.**>
         * @usage This hook method gets passed the current $cells
         * 	array as third parameter. This array contains values for the
         * 	icons/actions generated for each record in Web>List.
         * 	Each array entry is accessible by an index-key. The order of the
         * 	icons is dependend on the order of those array entries.
         */
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
                $hookObject = GeneralUtility::getUserObj($classData);
                if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
                    throw new UnexpectedValueException('$hookObject must implement interface \\TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567840);
                }
                $cells = $hookObject->makeControl($table, $row, $cells, $this);
            }
        }
        // Compile items into a DIV-element:
        return '
			<!-- CONTROL PANEL: ' . $table . ':' . $row['uid'] . ' -->
			<div class="typo3-DBctrl">' . implode('', $cells) . '</div>';
    }
 /**
  * Look for number of versions of a record
  *
  * @param string $table Table name
  * @param int $uid Record uid
  * @return int Number of versions for record, FALSE if none.
  */
 public function lookForOwnVersions($table, $uid)
 {
     $versions = BackendUtility::selectVersionsOfRecord($table, $uid, 'uid', null);
     if (is_array($versions)) {
         return count($versions);
     }
     return false;
 }
Beispiel #4
0
 /**
  * Creates the control panel for a single record in the listing.
  *
  * @param string $table The table
  * @param mixed[] $row The record for which to make the control panel.
  * @throws \UnexpectedValueException
  * @return string HTML table with the control panel (unless disabled)
  */
 public function makeControl($table, $row)
 {
     $module = $this->getModule();
     $rowUid = $row['uid'];
     if (ExtensionManagementUtility::isLoaded('version') && isset($row['_ORIG_uid'])) {
         $rowUid = $row['_ORIG_uid'];
     }
     $cells = array('primary' => array(), 'secondary' => array());
     // If the listed table is 'pages' we have to request the permission settings for each page:
     $localCalcPerms = 0;
     if ($table == 'pages') {
         $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
     }
     $permsEdit = $table === 'pages' && $this->getBackendUserAuthentication()->checkLanguageAccess(0) && $localCalcPerms & Permission::PAGE_EDIT || $table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT;
     $permsEdit = $this->overlayEditLockPermissions($table, $row, $permsEdit);
     // "Show" link (only pages and tt_content elements)
     if ($table == 'pages' || $table == 'tt_content') {
         $viewAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($table === 'tt_content' ? $this->id : $row['uid'], '', '', $table === 'tt_content' ? '#' . $row['uid'] : '')) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true) . '">' . $this->iconFactory->getIcon('actions-view', Icon::SIZE_SMALL)->render() . '</a>';
         $this->addActionToCellGroup($cells, $viewAction, 'view');
     }
     // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
     if ($permsEdit) {
         $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
         $iconIdentifier = 'actions-open';
         $overlayIdentifier = !$this->isEditable($table) ? 'overlay-readonly' : null;
         $editAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1)) . '" title="' . $this->getLanguageService()->getLL('edit', true) . '">' . $this->iconFactory->getIcon($iconIdentifier, Icon::SIZE_SMALL, $overlayIdentifier)->render() . '</a>';
     } else {
         $editAction = $this->spaceIcon;
     }
     $this->addActionToCellGroup($cells, $editAction, 'edit');
     // "Info": (All records)
     $onClick = 'top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', ' . (int) $row['uid'] . '); return false;';
     $viewBigAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $this->getLanguageService()->getLL('showInfo', true) . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>';
     $this->addActionToCellGroup($cells, $viewBigAction, 'viewBig');
     // "Move" wizard link for pages/tt_content elements:
     if ($permsEdit && ($table === 'tt_content' || $table === 'pages')) {
         $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $row['uid']) . ');';
         $linkTitleLL = $this->getLanguageService()->getLL('move_' . ($table === 'tt_content' ? 'record' : 'page'), true);
         $icon = $table == 'pages' ? $this->iconFactory->getIcon('actions-page-move', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL);
         $moveAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $linkTitleLL . '">' . $icon->render() . '</a>';
         $this->addActionToCellGroup($cells, $moveAction, 'move');
     }
     // If the table is NOT a read-only table, then show these links:
     if ($this->isEditable($table)) {
         // "Revert" link (history/undo)
         $moduleUrl = BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $row['uid']));
         $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue($moduleUrl) . ',\'#latest\');';
         $historyAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $this->getLanguageService()->getLL('history', true) . '">' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . '</a>';
         $this->addActionToCellGroup($cells, $historyAction, 'history');
         // Versioning:
         if (ExtensionManagementUtility::isLoaded('version') && !ExtensionManagementUtility::isLoaded('workspaces')) {
             $vers = BackendUtility::selectVersionsOfRecord($table, $row['uid'], 'uid', $this->getBackendUserAuthentication()->workspace, false, $row);
             // If table can be versionized.
             if (is_array($vers)) {
                 $href = BackendUtility::getModuleUrl('web_txversionM1', array('table' => $table, 'uid' => $row['uid']));
                 $versionAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' . $this->getLanguageService()->getLL('displayVersions', true) . '">' . $this->iconFactory->getIcon('actions-version-page-open', Icon::SIZE_SMALL)->render() . '</a>';
                 $this->addActionToCellGroup($cells, $versionAction, 'version');
             }
         }
         // "Edit Perms" link:
         if ($table === 'pages' && $this->getBackendUserAuthentication()->check('modules', 'system_BeuserTxPermission') && ExtensionManagementUtility::isLoaded('beuser')) {
             $href = BackendUtility::getModuleUrl('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&return_id=' . $row['uid'] . '&edit=1';
             $permsAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' . $this->getLanguageService()->getLL('permissions', true) . '">' . $this->iconFactory->getIcon('status-status-locked', Icon::SIZE_SMALL)->render() . '</a>';
             $this->addActionToCellGroup($cells, $permsAction, 'perms');
         }
         // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row
         // or if default values can depend on previous record):
         if (($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) {
             if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT || $table === 'pages' && $this->calcPerms & Permission::PAGE_NEW) {
                 if ($this->showNewRecLink($table)) {
                     $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
                     $icon = $table == 'pages' ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL);
                     $newAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1)) . '" title="' . $this->getLanguageService()->getLL('new' . ($table == 'pages ' ? 'Page' : 'Record'), true) . '">' . $icon->render() . '</a>';
                     $this->addActionToCellGroup($cells, $newAction, 'new');
                 }
             }
         }
         // "Up/Down" links
         if ($permsEdit && $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
             if (isset($this->currentTable['prev'][$row['uid']])) {
                 // Up
                 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
                 $moveUpAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');') . '" title="' . $this->getLanguageService()->getLL('moveUp', true) . '">' . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . '</a>';
             } else {
                 $moveUpAction = $this->spaceIcon;
             }
             $this->addActionToCellGroup($cells, $moveUpAction, 'moveUp');
             if ($this->currentTable['next'][$row['uid']]) {
                 // Down
                 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
                 $moveDownAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');') . '" title="' . $this->getLanguageService()->getLL('moveDown', true) . '">' . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . '</a>';
             } else {
                 $moveDownAction = $this->spaceIcon;
             }
             $this->addActionToCellGroup($cells, $moveDownAction, 'moveDown');
         }
         // "Hide/Unhide" links:
         $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
         if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $hiddenField))) {
             if ($this->isRecordCurrentBackendUser($table, $row)) {
                 $hideAction = $this->spaceIcon;
             } else {
                 $hideTitle = $this->getLanguageService()->getLL('hide' . ($table == 'pages' ? 'Page' : ''), true);
                 $unhideTitle = $this->getLanguageService()->getLL('unHide' . ($table == 'pages' ? 'Page' : ''), true);
                 if ($row[$hiddenField]) {
                     $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
                     $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="hidden" href="#"' . ' data-params="' . htmlspecialchars($params) . '"' . ' title="' . $unhideTitle . '"' . ' data-toggle-title="' . $hideTitle . '">' . $this->iconFactory->getIcon('actions-edit-unhide', Icon::SIZE_SMALL)->render() . '</a>';
                 } else {
                     $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
                     $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="visible" href="#"' . ' data-params="' . htmlspecialchars($params) . '"' . ' title="' . $hideTitle . '"' . ' data-toggle-title="' . $unhideTitle . '">' . $this->iconFactory->getIcon('actions-edit-hide', Icon::SIZE_SMALL)->render() . '</a>';
                 }
             }
             $this->addActionToCellGroup($cells, $hideAction, 'hide');
         }
         // "Delete" link:
         if ($permsEdit && ($table === 'pages' && $localCalcPerms & Permission::PAGE_DELETE || $table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT)) {
             // Check if the record version is in "deleted" state, because that will switch the action to "restore"
             if ($this->getBackendUserAuthentication()->workspace > 0 && isset($row['t3ver_state']) && (int) $row['t3ver_state'] === 2) {
                 $actionName = 'restore';
                 $refCountMsg = '';
             } else {
                 $actionName = 'delete';
                 $refCountMsg = BackendUtility::referenceCount($table, $row['uid'], ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToRecord'), $this->getReferenceCount($table, $row['uid'])) . BackendUtility::translationCount($table, $row['uid'], ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord'));
             }
             if ($this->isRecordCurrentBackendUser($table, $row)) {
                 $deleteAction = $this->spaceIcon;
             } else {
                 $titleOrig = BackendUtility::getRecordTitle($table, $row, false, true);
                 $title = GeneralUtility::slashJS(GeneralUtility::fixed_lgd_cs($titleOrig, $this->fixedL), true);
                 $warningText = $this->getLanguageService()->getLL($actionName . 'Warning') . ' "' . $title . '" ' . '[' . $table . ':' . $row['uid'] . ']' . $refCountMsg;
                 $params = 'cmd[' . $table . '][' . $row['uid'] . '][delete]=1';
                 $icon = $this->iconFactory->getIcon('actions-edit-' . $actionName, Icon::SIZE_SMALL)->render();
                 $linkTitle = $this->getLanguageService()->getLL($actionName, true);
                 $deleteAction = '<a class="btn btn-default t3js-record-delete" href="#" ' . ' data-l10parent="' . htmlspecialchars($row['l10n_parent']) . '"' . ' data-params="' . htmlspecialchars($params) . '" data-title="' . htmlspecialchars($titleOrig) . '"' . ' data-message="' . htmlspecialchars($warningText) . '" title="' . $linkTitle . '"' . '>' . $icon . '</a>';
             }
         } else {
             $deleteAction = $this->spaceIcon;
         }
         $this->addActionToCellGroup($cells, $deleteAction, 'delete');
         // "Levels" links: Moving pages into new levels...
         if ($permsEdit && $table == 'pages' && !$this->searchLevels) {
             // Up (Paste as the page right after the current parent page)
             if ($this->calcPerms & Permission::PAGE_NEW) {
                 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . -$this->id;
                 $moveLeftAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');') . '" title="' . $this->getLanguageService()->getLL('prevLevel', true) . '">' . $this->iconFactory->getIcon('actions-move-left', Icon::SIZE_SMALL)->render() . '</a>';
                 $this->addActionToCellGroup($cells, $moveLeftAction, 'moveLeft');
             }
             // Down (Paste as subpage to the page right above)
             if ($this->currentTable['prevUid'][$row['uid']]) {
                 $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']]));
                 if ($localCalcPerms & Permission::PAGE_NEW) {
                     $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
                     $moveRightAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');') . '" title="' . $this->getLanguageService()->getLL('nextLevel', true) . '">' . $this->iconFactory->getIcon('actions-move-right', Icon::SIZE_SMALL)->render() . '</a>';
                 } else {
                     $moveRightAction = $this->spaceIcon;
                 }
             } else {
                 $moveRightAction = $this->spaceIcon;
             }
             $this->addActionToCellGroup($cells, $moveRightAction, 'moveRight');
         }
     }
     /**
      * @hook recStatInfoHooks: Allows to insert HTML before record icons on various places
      */
     if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
         $stat = '';
         $_params = array($table, $row['uid']);
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
             $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
         }
         $this->addActionToCellGroup($cells, $stat, 'stat');
     }
     /**
      * @hook makeControl: Allows to change control icons of records in list-module
      * @usage This hook method gets passed the current $cells array as third parameter.
      *        This array contains values for the icons/actions generated for each record in Web>List.
      *        Each array entry is accessible by an index-key.
      *        The order of the icons is depending on the order of those array entries.
      */
     if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
         // for compatibility reason, we move all icons to the rootlevel
         // before calling the hooks
         foreach ($cells as $section => $actions) {
             foreach ($actions as $actionKey => $action) {
                 $cells[$actionKey] = $action;
             }
         }
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
             $hookObject = GeneralUtility::getUserObj($classData);
             if (!$hookObject instanceof RecordListHookInterface) {
                 throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListHookInterface::class, 1195567840);
             }
             $cells = $hookObject->makeControl($table, $row, $cells, $this);
         }
         // now sort icons again into primary and secondary sections
         // after all hooks are processed
         $hookCells = $cells;
         foreach ($hookCells as $key => $value) {
             if ($key === 'primary' || $key === 'secondary') {
                 continue;
             }
             $this->addActionToCellGroup($cells, $value, $key);
         }
     }
     $output = '<!-- CONTROL PANEL: ' . $table . ':' . $row['uid'] . ' -->';
     foreach ($cells as $classification => $actions) {
         $visibilityClass = $classification !== 'primary' && !$module->MOD_SETTINGS['bigControlPanel'] ? 'collapsed' : 'expanded';
         if ($visibilityClass === 'collapsed') {
             $cellOutput = '';
             foreach ($actions as $action) {
                 $cellOutput .= $action;
             }
             $output .= ' <div class="btn-group">' . '<span id="actions_' . $table . '_' . $row['uid'] . '" class="btn-group collapse collapse-horizontal width">' . $cellOutput . '</span>' . '<a href="#actions_' . $table . '_' . $row['uid'] . '" class="btn btn-default collapsed" data-toggle="collapse" aria-expanded="false"><span class="t3-icon fa fa-ellipsis-h"></span></a>' . '</div>';
         } else {
             $output .= ' <div class="btn-group" role="group">' . implode('', $actions) . '</div>';
         }
     }
     return $output;
 }
Beispiel #5
0
 /**
  * Recursive traversal of page tree:
  *
  * @param int $rootID Page root id (must be online, valid page record - or zero for page tree root)
  * @param int $depth Depth
  * @param int $echoLevel Echo Level
  * @param string $callBack Call back function (from this class or subclass)
  * @param bool $versionSwapmode DON'T set from outside, internal. (indicates we are inside a version of a page)
  * @param int $rootIsVersion DON'T set from outside, internal. (1: Indicates that rootID is a version of a page, 2: ...that it is even a version of a version (which triggers a warning!)
  * @param string $accumulatedPath Internal string that accumulates the path
  * @return void
  * @access private
  */
 public function genTree_traverse($rootID, $depth, $echoLevel = 0, $callBack = '', $versionSwapmode = false, $rootIsVersion = 0, $accumulatedPath = '')
 {
     // Register page:
     $this->recStats['all']['pages'][$rootID] = $rootID;
     $pageRecord = BackendUtility::getRecordRaw('pages', 'uid=' . (int) $rootID, 'deleted,title,t3ver_count,t3ver_wsid');
     $accumulatedPath .= '/' . $pageRecord['title'];
     // Register if page is deleted:
     if ($pageRecord['deleted']) {
         $this->recStats['deleted']['pages'][$rootID] = $rootID;
     }
     // If rootIsVersion is set it means that the input rootID is that of a version of a page. See below where the recursive call is made.
     if ($rootIsVersion) {
         $this->recStats['versions']['pages'][$rootID] = $rootID;
         // If it has been published and is in archive now...
         if ($pageRecord['t3ver_count'] >= 1 && $pageRecord['t3ver_wsid'] == 0) {
             $this->recStats['versions_published']['pages'][$rootID] = $rootID;
         }
         // If it has been published and is in archive now...
         if ($pageRecord['t3ver_wsid'] == 0) {
             $this->recStats['versions_liveWS']['pages'][$rootID] = $rootID;
         }
         // If it doesn't belong to a workspace...
         if (!isset($this->workspaceIndex[$pageRecord['t3ver_wsid']])) {
             $this->recStats['versions_lost_workspace']['pages'][$rootID] = $rootID;
         }
         // In case the rootID is a version inside a versioned page
         if ($rootIsVersion == 2) {
             $this->recStats['versions_inside_versioned_page']['pages'][$rootID] = $rootID;
         }
     }
     if ($echoLevel > 0) {
         echo LF . $accumulatedPath . ' [' . $rootID . ']' . ($pageRecord['deleted'] ? ' (DELETED)' : '') . ($this->recStats['versions_published']['pages'][$rootID] ? ' (PUBLISHED)' : '');
     }
     if ($echoLevel > 1 && $this->recStats['versions_lost_workspace']['pages'][$rootID]) {
         echo LF . '	ERROR! This version belongs to non-existing workspace (' . $pageRecord['t3ver_wsid'] . ')!';
     }
     if ($echoLevel > 1 && $this->recStats['versions_inside_versioned_page']['pages'][$rootID]) {
         echo LF . '	WARNING! This version is inside an already versioned page or branch!';
     }
     // Call back:
     if ($callBack) {
         $this->{$callBack}('pages', $rootID, $echoLevel, $versionSwapmode, $rootIsVersion);
     }
     // Traverse tables of records that belongs to page:
     foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
         if ($tableName !== 'pages') {
             // Select all records belonging to page:
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
             $queryBuilder->getRestrictions()->removeAll();
             $queryBuilder->select('uid')->from($tableName)->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($rootID, \PDO::PARAM_INT)));
             if ($GLOBALS['TCA'][$tableName]['ctrl']['delete']) {
                 $queryBuilder->addSelect($GLOBALS['TCA'][$tableName]['ctrl']['delete']);
             }
             if (!$this->genTree_traverseDeleted) {
                 $queryBuilder->getRestrictions()->add(DeletedRestriction::class);
             }
             $result = $queryBuilder->execute();
             $count = $result->rowCount();
             if ($count) {
                 if ($echoLevel == 2) {
                     echo LF . '	\\-' . $tableName . ' (' . $count . ')';
                 }
             }
             while ($rowSub = $result->fetch()) {
                 if ($echoLevel == 3) {
                     echo LF . '	\\-' . $tableName . ':' . $rowSub['uid'];
                 }
                 // If the rootID represents an "element" or "page" version type, we must check if the record from this table is allowed to belong to this:
                 if ($versionSwapmode) {
                     // This is illegal records under a versioned page - therefore not registered in $this->recStats['all'] so they should be orphaned:
                     $this->recStats['illegal_record_under_versioned_page'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                     if ($echoLevel > 1) {
                         echo LF . '		ERROR! Illegal record (' . $tableName . ':' . $rowSub['uid'] . ') under versioned page!';
                     }
                 } else {
                     $this->recStats['all'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                     // Register deleted:
                     if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $rowSub[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) {
                         $this->recStats['deleted'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel == 3) {
                             echo ' (DELETED)';
                         }
                     }
                     // Check location of records regarding tree root:
                     if (!$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] && $rootID == 0) {
                         $this->recStats['misplaced_at_rootlevel'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel > 1) {
                             echo LF . '		ERROR! Misplaced record (' . $tableName . ':' . $rowSub['uid'] . ') on rootlevel!';
                         }
                     }
                     if ($GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] == 1 && $rootID > 0) {
                         $this->recStats['misplaced_inside_tree'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel > 1) {
                             echo LF . '		ERROR! Misplaced record (' . $tableName . ':' . $rowSub['uid'] . ') inside page tree!';
                         }
                     }
                     // Traverse plugins:
                     if ($callBack) {
                         $this->{$callBack}($tableName, $rowSub['uid'], $echoLevel, $versionSwapmode, $rootIsVersion);
                     }
                     // Add any versions of those records:
                     if ($this->genTree_traverseVersions) {
                         $versions = BackendUtility::selectVersionsOfRecord($tableName, $rowSub['uid'], 'uid,t3ver_wsid,t3ver_count' . ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] : ''), null, true);
                         if (is_array($versions)) {
                             foreach ($versions as $verRec) {
                                 if (!$verRec['_CURRENT_VERSION']) {
                                     if ($echoLevel == 3) {
                                         echo LF . '		\\-[#OFFLINE VERSION: WS#' . $verRec['t3ver_wsid'] . '/Cnt:' . $verRec['t3ver_count'] . '] ' . $tableName . ':' . $verRec['uid'] . ')';
                                     }
                                     $this->recStats['all'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     // Register deleted:
                                     if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $verRec[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) {
                                         $this->recStats['deleted'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel == 3) {
                                             echo ' (DELETED)';
                                         }
                                     }
                                     // Register version:
                                     $this->recStats['versions'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     if ($verRec['t3ver_count'] >= 1 && $verRec['t3ver_wsid'] == 0) {
                                         // Only register published versions in LIVE workspace (published versions in draft workspaces are allowed)
                                         $this->recStats['versions_published'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel == 3) {
                                             echo ' (PUBLISHED)';
                                         }
                                     }
                                     if ($verRec['t3ver_wsid'] == 0) {
                                         $this->recStats['versions_liveWS'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     }
                                     if (!isset($this->workspaceIndex[$verRec['t3ver_wsid']])) {
                                         $this->recStats['versions_lost_workspace'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel > 1) {
                                             echo LF . '		ERROR! Version (' . $tableName . ':' . $verRec['uid'] . ') belongs to non-existing workspace (' . $verRec['t3ver_wsid'] . ')!';
                                         }
                                     }
                                     // In case we are inside a versioned branch, there should not exists versions inside that "branch".
                                     if ($versionSwapmode) {
                                         $this->recStats['versions_inside_versioned_page'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel > 1) {
                                             echo LF . '		ERROR! This version (' . $tableName . ':' . $verRec['uid'] . ') is inside an already versioned page or branch!';
                                         }
                                     }
                                     // Traverse plugins:
                                     if ($callBack) {
                                         $this->{$callBack}($tableName, $verRec['uid'], $echoLevel, $versionSwapmode, $rootIsVersion);
                                     }
                                 }
                             }
                         }
                         unset($versions);
                     }
                 }
             }
         }
     }
     unset($resSub);
     unset($rowSub);
     // Find subpages to root ID and traverse (only when rootID is not a version or is a branch-version):
     if ($depth > 0) {
         $depth--;
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         $queryBuilder->getRestrictions()->removeAll();
         if (!$this->genTree_traverseDeleted) {
             $queryBuilder->getRestrictions()->add(DeletedRestriction::class);
         }
         $queryBuilder->select('uid')->from('pages')->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($rootID, \PDO::PARAM_INT)))->orderBy('sorting');
         $result = $queryBuilder->execute();
         while ($row = $result->fetch()) {
             $this->genTree_traverse($row['uid'], $depth, $echoLevel, $callBack, $versionSwapmode, 0, $accumulatedPath);
         }
     }
     // Add any versions of pages
     if ($rootID > 0 && $this->genTree_traverseVersions) {
         $versions = BackendUtility::selectVersionsOfRecord('pages', $rootID, 'uid,t3ver_oid,t3ver_wsid,t3ver_count', null, true);
         if (is_array($versions)) {
             foreach ($versions as $verRec) {
                 if (!$verRec['_CURRENT_VERSION']) {
                     $this->genTree_traverse($verRec['uid'], $depth, $echoLevel, $callBack, true, $versionSwapmode ? 2 : 1, $accumulatedPath . ' [#OFFLINE VERSION: WS#' . $verRec['t3ver_wsid'] . '/Cnt:' . $verRec['t3ver_count'] . ']');
                 }
             }
         }
     }
 }
Beispiel #6
0
 /**
  * Delete versions for element from any table
  *
  * @param string $table Table name
  * @param int $uid Record UID
  * @param bool $forceHardDelete If TRUE, the "deleted" flag is ignored if applicable for record and the record is deleted COMPLETELY!
  * @return void
  */
 public function deleteVersionsForRecord($table, $uid, $forceHardDelete)
 {
     $versions = BackendUtility::selectVersionsOfRecord($table, $uid, 'uid,pid,t3ver_wsid,t3ver_state', $this->BE_USER->workspace ?: null);
     if (is_array($versions)) {
         foreach ($versions as $verRec) {
             if (!$verRec['_CURRENT_VERSION']) {
                 if ($table == 'pages') {
                     $this->deletePages($verRec['uid'], true, $forceHardDelete);
                 } else {
                     $this->deleteRecord($table, $verRec['uid'], true, $forceHardDelete);
                 }
                 // Delete move-placeholder
                 $versionState = VersionState::cast($verRec['t3ver_state']);
                 if ($versionState->equals(VersionState::MOVE_POINTER)) {
                     $versionMovePlaceholder = BackendUtility::getMovePlaceholder($table, $uid, 'uid', $verRec['t3ver_wsid']);
                     $this->deleteEl($table, $versionMovePlaceholder['uid'], true, $forceHardDelete);
                 }
             }
         }
     }
 }
Beispiel #7
0
 /**
  * Delete versions for element from any table
  *
  * @param string $table Table name
  * @param int $uid Record UID
  * @param bool $forceHardDelete If TRUE, the "deleted" flag is ignored if applicable for record and the record is deleted COMPLETELY!
  * @return void
  */
 public function deleteVersionsForRecord($table, $uid, $forceHardDelete)
 {
     $versions = BackendUtility::selectVersionsOfRecord($table, $uid, 'uid,pid', $this->BE_USER->workspace);
     if (is_array($versions)) {
         foreach ($versions as $verRec) {
             if (!$verRec['_CURRENT_VERSION']) {
                 if ($table == 'pages') {
                     $this->deletePages($verRec['uid'], TRUE, $forceHardDelete);
                 } else {
                     $this->deleteRecord($table, $verRec['uid'], TRUE, $forceHardDelete);
                 }
             }
         }
     }
 }
 /**
  * Find orphan records
  * VERY CPU and memory intensive since it will look up the whole page tree!
  *
  * @return array
  */
 public function main()
 {
     // Initialize result array:
     $resultArray = array('message' => $this->cli_help['name'] . LF . LF . $this->cli_help['description'], 'headers' => array('versions' => array('All versions', 'Showing all versions of records found', 0), 'versions_published' => array('All published versions', 'This is all records that has been published and can therefore be removed permanently', 1), 'versions_liveWS' => array('All versions in Live workspace', 'This is all records that are offline versions in the Live workspace. You may wish to flush these if you only use workspaces for versioning since then you might find lots of versions piling up in the live workspace which have simply been disconnected from the workspace before they were published.', 1), 'versions_lost_workspace' => array('Versions outside a workspace', 'Versions that has lost their connection to a workspace in TYPO3.', 3), 'versions_inside_versioned_page' => array('Versions in versions', 'Versions inside an already versioned page. Something that is confusing to users and therefore should not happen but is technically possible.', 2), 'versions_unused_placeholders' => array('Unused placeholder records', 'Placeholder records which are not used anymore by offline versions.', 2), 'versions_move_placeholders_ok' => array('Move placeholders', 'Move-to placeholder records which has good integrity', 0), 'versions_move_placeholders_bad' => array('Move placeholders with bad integrity', 'Move-to placeholder records which has bad integrity', 2), 'versions_move_id_check' => array('Checking if t3ver_move_id is correct', 't3ver_move_id must only be set with online records having t3ver_state=3.', 2)), 'versions' => array());
     $startingPoint = $this->cli_isArg('--pid') ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->cli_argValue('--pid'), 0) : 0;
     $depth = $this->cli_isArg('--depth') ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->cli_argValue('--depth'), 0) : 1000;
     $this->genTree($startingPoint, $depth, (int) $this->cli_argValue('--echotree'));
     $resultArray['versions'] = $this->recStats['versions'];
     $resultArray['versions_published'] = $this->recStats['versions_published'];
     $resultArray['versions_liveWS'] = $this->recStats['versions_liveWS'];
     $resultArray['versions_lost_workspace'] = $this->recStats['versions_lost_workspace'];
     $resultArray['versions_inside_versioned_page'] = $this->recStats['versions_inside_versioned_page'];
     // Finding all placeholders with no records attached!
     $resultArray['versions_unused_placeholders'] = array();
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if ($cfg['ctrl']['versioningWS']) {
             $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid', $table, 't3ver_state=' . new VersionState(VersionState::NEW_PLACEHOLDER) . ' AND pid>=0' . BackendUtility::deleteClause($table));
             foreach ($placeHolders as $phrec) {
                 if (count(BackendUtility::selectVersionsOfRecord($table, $phrec['uid'], 'uid', '*', null)) <= 1) {
                     $resultArray['versions_unused_placeholders'][GeneralUtility::shortMD5($table . ':' . $phrec['uid'])] = $table . ':' . $phrec['uid'];
                 }
             }
         }
     }
     asort($resultArray['versions_unused_placeholders']);
     // Finding all move placeholders with inconsistencies:
     $resultArray['versions_move_placeholders_ok'] = array();
     $resultArray['versions_move_placeholders_bad'] = array();
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if (BackendUtility::isTableWorkspaceEnabled($table)) {
             $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,t3ver_move_id,t3ver_wsid,t3ver_state', $table, 't3ver_state=' . new VersionState(VersionState::MOVE_PLACEHOLDER) . ' AND pid>=0' . BackendUtility::deleteClause($table));
             foreach ($placeHolders as $phrec) {
                 $shortID = GeneralUtility::shortMD5($table . ':' . $phrec['uid']);
                 if ((int) $phrec['t3ver_wsid'] != 0) {
                     $phrecCopy = $phrec;
                     if (BackendUtility::movePlhOL($table, $phrec)) {
                         if ($wsAlt = BackendUtility::getWorkspaceVersionOfRecord($phrecCopy['t3ver_wsid'], $table, $phrec['uid'], 'uid,pid,t3ver_state')) {
                             if (!VersionState::cast($wsAlt['t3ver_state'])->equals(VersionState::MOVE_POINTER)) {
                                 $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'State for version was not "4" as it should be!', $phrecCopy);
                             } else {
                                 $resultArray['versions_move_placeholders_ok'][$shortID] = array($table . ':' . $phrec['uid'], 'PLH' => $phrecCopy, 'online' => $phrec, 'PNT' => $wsAlt);
                             }
                         } else {
                             $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'No version was found for online record to be moved. A version must exist.', $phrecCopy);
                         }
                     } else {
                         $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'Did not find online record for "t3ver_move_id" value ' . $phrec['t3ver_move_id'], $phrec);
                     }
                 } else {
                     $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'Placeholder was not assigned a workspace value in t3ver_wsid.', $phrec);
                 }
             }
         }
     }
     ksort($resultArray['versions_move_placeholders_ok']);
     ksort($resultArray['versions_move_placeholders_bad']);
     // Finding move_id_check inconsistencies:
     $resultArray['versions_move_id_check'] = array();
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if (BackendUtility::isTableWorkspaceEnabled($table)) {
             $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,t3ver_move_id,t3ver_wsid,t3ver_state', $table, 't3ver_move_id<>0' . BackendUtility::deleteClause($table));
             foreach ($placeHolders as $phrec) {
                 if (VersionState::cast($phrec['t3ver_state'])->equals(VersionState::MOVE_PLACEHOLDER)) {
                     if ($phrec['pid'] != -1) {
                     } else {
                         $resultArray['versions_move_id_check'][] = array($table . ':' . $phrec['uid'], 'Record was offline, must not be!', $phrec);
                     }
                 } else {
                     $resultArray['versions_move_id_check'][] = array($table . ':' . $phrec['uid'], 'Record had t3ver_move_id set to "' . $phrec['t3ver_move_id'] . '" while having t3ver_state=' . $phrec['t3ver_state'], $phrec);
                 }
             }
         }
     }
     return $resultArray;
 }
Beispiel #9
0
    /**
     * Creates the version selector for the page id inputted.
     * Moved out of the core file \TYPO3\CMS\Backend\Template\DocumentTemplate
     *
     * @param int $id Page id to create selector for.
     * @param bool $noAction If set, there will be no button for swapping page.
     * @return string
     * @see \TYPO3\CMS\Backend\Template\DocumentTemplate
     */
    public function getVersionSelector($id, $noAction = false)
    {
        if ($id <= 0) {
            return '';
        }
        if ($GLOBALS['BE_USER']->workspace == 0) {
            // Get Current page record:
            $curPage = BackendUtility::getRecord('pages', $id);
            // If the selected page is not online, find the right ID
            $onlineId = $curPage['pid'] == -1 ? $curPage['t3ver_oid'] : $id;
            // Select all versions of online version:
            $versions = BackendUtility::selectVersionsOfRecord('pages', $onlineId, 'uid,pid,t3ver_label,t3ver_oid,t3ver_wsid,t3ver_id', null);
            // If more than one was found...:
            if (count($versions) > 1) {
                // Create selector box entries:
                $opt = array();
                foreach ($versions as $vRow) {
                    if ($vRow['uid'] == $onlineId) {
                        // Live version
                        $label = '[' . $GLOBALS['LANG']->sL('LLL:EXT:version/Resources/Private/Language/locallang.xlf:versionSelect.live', true) . ']';
                    } else {
                        $label = $vRow['t3ver_label'] . ' (' . $GLOBALS['LANG']->sL('LLL:EXT:version/Resources/Private/Language/locallang.xlf:versionId', true) . ' ' . $vRow['t3ver_id'] . ($vRow['t3ver_wsid'] != 0 ? ' ' . $GLOBALS['LANG']->sL('LLL:EXT:version/Resources/Private/Language/locallang.xlf:workspaceId', true) . ' ' . $vRow['t3ver_wsid'] : '') . ')';
                    }
                    $opt[] = '<option value="' . htmlspecialchars(GeneralUtility::linkThisScript(array('id' => $vRow['uid']))) . '"' . ($id == $vRow['uid'] ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
                }
                /** @var $iconFactory \TYPO3\CMS\Core\Imaging\IconFactory */
                $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
                // Add management link:
                $management = '
					<a class="btn btn-default" href="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl('web_txversionM1', array('table' => 'pages', 'uid' => $onlineId))) . '">
						' . $iconFactory->getIcon('actions-version-open', Icon::SIZE_SMALL)->render() . '
						' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.mgm', true) . '
					</a>';
                // Create onchange handler:
                $onChange = 'window.location.href=this.options[this.selectedIndex].value;';
                // Controls:
                if ($id == $onlineId) {
                    $controls = '<strong class="text-success">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.online', true) . '</strong>';
                } elseif (!$noAction) {
                    $href = $GLOBALS['TBE_TEMPLATE']->issueCommand('&cmd[pages][' . $onlineId . '][version][swapWith]=' . $id . '&cmd[pages][' . $onlineId . '][version][action]=swap', GeneralUtility::linkThisScript(array('id' => $onlineId)));
                    $controls = '
						<a href="' . htmlspecialchars($href) . '" class="btn btn-default" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.swapPage', true) . '">
							' . $iconFactory->getIcon('actions-version-swap-version', Icon::SIZE_SMALL)->render() . '
							' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:ver.swap', true) . '
						</a>';
                }
                // Write out HTML code:
                return '
					<!--
						Version selector:
					-->
					<div id="typo3-version-selector" class="form-inline form-inline-spaced">
						<div class="form-group">
							<label for="version-selector">' . $GLOBALS['LANG']->sL('LLL:EXT:version/Resources/Private/Language/locallang.xlf:versionSelect.label', true) . '</label>
							<select id="version-selector" class="form-control" onchange="' . htmlspecialchars($onChange) . '">
								' . implode('', $opt) . '
							</select>
						</div>
						<div class="form-group">
							' . $controls . '
						</div>
						<div class="form-group">
							' . $management . '
						</div>
					</div>
				';
            }
        }
    }
 /**
  * Recursive traversal of page tree:
  *
  * @param integer $rootID Page root id (must be online, valid page record - or zero for page tree root)
  * @param integer $depth Depth
  * @param integer $echoLevel Echo Level
  * @param string $callBack Call back function (from this class or subclass)
  * @param string $versionSwapmode DON'T set from outside, internal. (indicates we are inside a version of a page) - will be "SWAPMODE:-1" or empty
  * @param integer $rootIsVersion DON'T set from outside, internal. (1: Indicates that rootID is a version of a page, 2: ...that it is even a version of a version (which triggers a warning!)
  * @param string $accumulatedPath Internal string that accumulates the path
  * @return void
  * @access private
  * @todo $versionSwapmode needs to be cleaned up, since page and branch version (0, 1) does not exist anymore
  * @todo Define visibility
  */
 public function genTree_traverse($rootID, $depth, $echoLevel = 0, $callBack = '', $versionSwapmode = '', $rootIsVersion = 0, $accumulatedPath = '')
 {
     // Register page:
     $this->recStats['all']['pages'][$rootID] = $rootID;
     $pageRecord = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordRaw('pages', 'uid=' . intval($rootID), 'deleted,title,t3ver_count,t3ver_wsid');
     $accumulatedPath .= '/' . $pageRecord['title'];
     // Register if page is deleted:
     if ($pageRecord['deleted']) {
         $this->recStats['deleted']['pages'][$rootID] = $rootID;
     }
     // If rootIsVersion is set it means that the input rootID is that of a version of a page. See below where the recursive call is made.
     if ($rootIsVersion) {
         $this->recStats['versions']['pages'][$rootID] = $rootID;
         // If it has been published and is in archive now...
         if ($pageRecord['t3ver_count'] >= 1 && $pageRecord['t3ver_wsid'] == 0) {
             $this->recStats['versions_published']['pages'][$rootID] = $rootID;
         }
         // If it has been published and is in archive now...
         if ($pageRecord['t3ver_wsid'] == 0) {
             $this->recStats['versions_liveWS']['pages'][$rootID] = $rootID;
         }
         // If it doesn't belong to a workspace...
         if (!isset($this->workspaceIndex[$pageRecord['t3ver_wsid']])) {
             $this->recStats['versions_lost_workspace']['pages'][$rootID] = $rootID;
         }
         // In case the rootID is a version inside a versioned page
         if ($rootIsVersion == 2) {
             $this->recStats['versions_inside_versioned_page']['pages'][$rootID] = $rootID;
         }
     }
     if ($echoLevel > 0) {
         echo LF . $accumulatedPath . ' [' . $rootID . ']' . ($pageRecord['deleted'] ? ' (DELETED)' : '') . ($this->recStats['versions_published']['pages'][$rootID] ? ' (PUBLISHED)' : '');
     }
     if ($echoLevel > 1 && $this->recStats['versions_lost_workspace']['pages'][$rootID]) {
         echo LF . '	ERROR! This version belongs to non-existing workspace (' . $pageRecord['t3ver_wsid'] . ')!';
     }
     if ($echoLevel > 1 && $this->recStats['versions_inside_versioned_page']['pages'][$rootID]) {
         echo LF . '	WARNING! This version is inside an already versioned page or branch!';
     }
     // Call back:
     if ($callBack) {
         $this->{$callBack}('pages', $rootID, $echoLevel, $versionSwapmode, $rootIsVersion);
     }
     $pt3 = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
     // Traverse tables of records that belongs to page:
     foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
         if ($tableName != 'pages') {
             // Select all records belonging to page:
             $pt4 = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
             $resSub = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid' . ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] : ''), $tableName, 'pid=' . intval($rootID) . ($this->genTree_traverseDeleted ? '' : \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($tableName)));
             $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL']['(ALL)'] += \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt4;
             $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL'][$tableName] += \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt4;
             $pt5 = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
             $count = $GLOBALS['TYPO3_DB']->sql_num_rows($resSub);
             if ($count) {
                 if ($echoLevel == 2) {
                     echo LF . '	\\-' . $tableName . ' (' . $count . ')';
                 }
             }
             while ($rowSub = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resSub)) {
                 if ($echoLevel == 3) {
                     echo LF . '	\\-' . $tableName . ':' . $rowSub['uid'];
                 }
                 // If the rootID represents an "element" or "page" version type, we must check if the record from this table is allowed to belong to this:
                 if ($versionSwapmode == 'SWAPMODE:-1' || $versionSwapmode == 'SWAPMODE:0' && !$GLOBALS['TCA'][$tableName]['ctrl']['versioning_followPages']) {
                     // This is illegal records under a versioned page - therefore not registered in $this->recStats['all'] so they should be orphaned:
                     $this->recStats['illegal_record_under_versioned_page'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                     if ($echoLevel > 1) {
                         echo LF . '		ERROR! Illegal record (' . $tableName . ':' . $rowSub['uid'] . ') under versioned page!';
                     }
                 } else {
                     $this->recStats['all'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                     // Register deleted:
                     if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $rowSub[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) {
                         $this->recStats['deleted'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel == 3) {
                             echo ' (DELETED)';
                         }
                     }
                     // Check location of records regarding tree root:
                     if (!$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] && $rootID == 0) {
                         $this->recStats['misplaced_at_rootlevel'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel > 1) {
                             echo LF . '		ERROR! Misplaced record (' . $tableName . ':' . $rowSub['uid'] . ') on rootlevel!';
                         }
                     }
                     if ($GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] == 1 && $rootID > 0) {
                         $this->recStats['misplaced_inside_tree'][$tableName][$rowSub['uid']] = $rowSub['uid'];
                         if ($echoLevel > 1) {
                             echo LF . '		ERROR! Misplaced record (' . $tableName . ':' . $rowSub['uid'] . ') inside page tree!';
                         }
                     }
                     // Traverse plugins:
                     if ($callBack) {
                         $this->{$callBack}($tableName, $rowSub['uid'], $echoLevel, $versionSwapmode, $rootIsVersion);
                     }
                     // Add any versions of those records:
                     if ($this->genTree_traverseVersions) {
                         $versions = \TYPO3\CMS\Backend\Utility\BackendUtility::selectVersionsOfRecord($tableName, $rowSub['uid'], 'uid,t3ver_wsid,t3ver_count' . ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] : ''), 0, TRUE);
                         if (is_array($versions)) {
                             foreach ($versions as $verRec) {
                                 if (!$verRec['_CURRENT_VERSION']) {
                                     if ($echoLevel == 3) {
                                         echo LF . '		\\-[#OFFLINE VERSION: WS#' . $verRec['t3ver_wsid'] . '/Cnt:' . $verRec['t3ver_count'] . '] ' . $tableName . ':' . $verRec['uid'] . ')';
                                     }
                                     $this->recStats['all'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     // Register deleted:
                                     if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $verRec[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) {
                                         $this->recStats['deleted'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel == 3) {
                                             echo ' (DELETED)';
                                         }
                                     }
                                     // Register version:
                                     $this->recStats['versions'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     if ($verRec['t3ver_count'] >= 1 && $verRec['t3ver_wsid'] == 0) {
                                         // Only register published versions in LIVE workspace (published versions in draft workspaces are allowed)
                                         $this->recStats['versions_published'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel == 3) {
                                             echo ' (PUBLISHED)';
                                         }
                                     }
                                     if ($verRec['t3ver_wsid'] == 0) {
                                         $this->recStats['versions_liveWS'][$tableName][$verRec['uid']] = $verRec['uid'];
                                     }
                                     if (!isset($this->workspaceIndex[$verRec['t3ver_wsid']])) {
                                         $this->recStats['versions_lost_workspace'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel > 1) {
                                             echo LF . '		ERROR! Version (' . $tableName . ':' . $verRec['uid'] . ') belongs to non-existing workspace (' . $verRec['t3ver_wsid'] . ')!';
                                         }
                                     }
                                     // In case we are inside a versioned branch, there should not exists versions inside that "branch".
                                     if ($versionSwapmode) {
                                         $this->recStats['versions_inside_versioned_page'][$tableName][$verRec['uid']] = $verRec['uid'];
                                         if ($echoLevel > 1) {
                                             echo LF . '		ERROR! This version (' . $tableName . ':' . $verRec['uid'] . ') is inside an already versioned page or branch!';
                                         }
                                     }
                                     // Traverse plugins:
                                     if ($callBack) {
                                         $this->{$callBack}($tableName, $verRec['uid'], $echoLevel, $versionSwapmode, $rootIsVersion);
                                     }
                                 }
                             }
                         }
                         unset($versions);
                     }
                 }
             }
             $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc']['(ALL)'] += \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt5;
             $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc'][$tableName] += \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt5;
         }
     }
     unset($resSub);
     unset($rowSub);
     $this->performanceStatistics['genTree_traverse():TraverseTables'] += \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt3;
     // Find subpages to root ID and traverse (only when rootID is not a version or is a branch-version):
     if (!$versionSwapmode || $versionSwapmode == 'SWAPMODE:1') {
         if ($depth > 0) {
             $depth--;
             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid=' . intval($rootID) . ($this->genTree_traverseDeleted ? '' : \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause('pages')), '', 'sorting');
             while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
                 $this->genTree_traverse($row['uid'], $depth, $echoLevel, $callBack, $versionSwapmode, 0, $accumulatedPath);
             }
         }
         // Add any versions of pages
         if ($rootID > 0 && $this->genTree_traverseVersions) {
             $versions = \TYPO3\CMS\Backend\Utility\BackendUtility::selectVersionsOfRecord('pages', $rootID, 'uid,t3ver_oid,t3ver_wsid,t3ver_count', 0, TRUE);
             if (is_array($versions)) {
                 foreach ($versions as $verRec) {
                     if (!$verRec['_CURRENT_VERSION']) {
                         $this->genTree_traverse($verRec['uid'], $depth, $echoLevel, $callBack, 'SWAPMODE:-1', $versionSwapmode ? 2 : 1, $accumulatedPath . ' [#OFFLINE VERSION: WS#' . $verRec['t3ver_wsid'] . '/Cnt:' . $verRec['t3ver_count'] . ']');
                     }
                 }
             }
         }
     }
 }
    /**
     * Creates the control panel for a single record in the listing.
     *
     * @param string $table The table
     * @param array $row The record for which to make the control panel.
     * @param string $level
     * @return string HTML table with the control panel (unless disabled)
     */
    public function makeControl($table, $row, $level)
    {
        if ($this->dontShowClipControlPanels) {
            return '';
        }
        $rowUid = $row['uid'];
        if (ExtensionManagementUtility::isLoaded('version') && isset($row['_ORIG_uid'])) {
            $rowUid = $row['_ORIG_uid'];
        }
        $cells = array();
        // If the listed table is 'pages' we have to request the permission settings for each page:
        if ($table == 'pages') {
            $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
        }
        // This expresses the edit permissions for this particular element:
        $permsEdit = $table == 'pages' && $localCalcPerms & 2 || $table != 'pages' && $this->calcPerms & 16;
        // "Show" link (only pages and tt_content elements)
        if ($table == 'pages' || $table == 'tt_content') {
            $cells['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($table === 'tt_content' ? $this->id : $row['uid'], $this->backPath, '', $table === 'tt_content' ? '#' . $row['uid'] : '')) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
        } elseif (!$this->table) {
            $cells['view'] = $this->spaceIcon;
        }
        // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
        if ($permsEdit) {
            $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
            $cells['edit'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('edit', TRUE) . '">' . ($GLOBALS['TCA'][$table]['ctrl']['readOnly'] ? IconUtility::getSpriteIcon('actions-document-open-read-only') : IconUtility::getSpriteIcon('actions-document-open')) . '</a>';
        } elseif (!$this->table) {
            $cells['edit'] = $this->spaceIcon;
        }
        // "Move" wizard link for pages/tt_content elements:
        if (($table == 'tt_content' && $permsEdit || $table == 'pages') && $level == 0) {
            $cells['move'] = '<a href="#" onclick="' . htmlspecialchars('return jumpExt(\'' . $this->backPath . 'move_el.php?table=' . $table . '&uid=' . $row['uid'] . '\');') . '" title="' . $GLOBALS['LANG']->getLL('move_' . ($table == 'tt_content' ? 'record' : 'page'), TRUE) . '">' . ($table == 'tt_content' ? IconUtility::getSpriteIcon('actions-document-move') : IconUtility::getSpriteIcon('actions-page-move')) . '</a>';
        } elseif (!$this->table || $level > 0) {
            $cells['move'] = $this->spaceIcon;
        }
        // If the extended control panel is enabled OR if we are seeing a single table:
        if ($GLOBALS['SOBE']->MOD_SETTINGS['bigControlPanel'] || $this->table) {
            // "Info": (All records)
            $cells['viewBig'] = '<a href="#" onclick="' . htmlspecialchars('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;') . '" title="' . $GLOBALS['LANG']->getLL('showInfo', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-info') . '</a>';
            // If the table is NOT a read-only table, then show these links:
            if (!$GLOBALS['TCA'][$table]['ctrl']['readOnly']) {
                // "Revert" link (history/undo)
                $cells['history'] = '<a href="#" onclick="' . htmlspecialchars('return jumpExt(' . GeneralUtility::quoteJSvalue($this->backPath . BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $row['uid']))) . ',\'#latest\');') . '" title="' . $GLOBALS['LANG']->getLL('history', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-history-open') . '</a>';
                // Versioning:
                if (ExtensionManagementUtility::isLoaded('version') && !ExtensionManagementUtility::isLoaded('workspaces')) {
                    $vers = BackendUtility::selectVersionsOfRecord($table, $row['uid'], 'uid', $GLOBALS['BE_USER']->workspace, FALSE, $row);
                    // If table can be versionized.
                    if (is_array($vers)) {
                        $versionIcon = 'no-version';
                        if (count($vers) > 1) {
                            $versionIcon = count($vers) - 1;
                        }
                        $cells['version'] = '<a href="' . htmlspecialchars($this->backPath . BackendUtility::getModuleUrl('web_txversionM1', array('table' => $table, 'uid' => $row['uid']))) . '" title="' . $GLOBALS['LANG']->getLL('displayVersions', TRUE) . '">' . IconUtility::getSpriteIcon('status-version-' . $versionIcon) . '</a>';
                    } elseif (!$this->table) {
                        $cells['version'] = $this->spaceIcon;
                    }
                }
                // "Edit Perms" link:
                if ($table == 'pages' && $GLOBALS['BE_USER']->check('modules', 'web_perm') && ExtensionManagementUtility::isLoaded('perm')) {
                    $cells['perms'] = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_perm') . '&id=' . $row['uid'] . '&return_id=' . $row['uid'] . '&edit=1') . '" title="' . $GLOBALS['LANG']->getLL('permissions', TRUE) . '">' . IconUtility::getSpriteIcon('status-status-locked') . '</a>';
                } elseif ((!$this->table || $level > 0) && $GLOBALS['BE_USER']->check('modules', 'web_perm')) {
                    $cells['perms'] = $this->spaceIcon;
                }
                // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row or if default values can depend on previous record):
                if ($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
                    if ($table != 'pages' && $this->calcPerms & 16 || $table == 'pages' && $this->calcPerms & 8) {
                        if ($this->showNewRecLink($table)) {
                            $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
                            $cells['new'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('new' . ($table == 'pages ' ? 'Page' : 'Record'), TRUE) . '">' . ($table == 'pages' ? IconUtility::getSpriteIcon('actions-page-new') : IconUtility::getSpriteIcon('actions-document-new')) . '</a>';
                        }
                    }
                } elseif (!$this->table) {
                    $cells['new'] = $this->spaceIcon;
                }
                // "Up/Down" links
                if ($permsEdit && $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
                    if (isset($this->currentTable['prev'][$row['uid']]) && $this->showMoveUp === TRUE) {
                        // Up
                        if ($this->lastMoveDownParams) {
                            $params = $this->lastMoveDownParams;
                        } else {
                            $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
                        }
                        $cells['moveUp'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('moveUp', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-up') . '</a>';
                    } else {
                        $cells['moveUp'] = $this->spaceIcon;
                    }
                    if ($this->currentTable['next'][$row['uid']] && $this->showMoveDown === TRUE) {
                        // Down
                        $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
                        $this->lastMoveDownParams = $params;
                        $cells['moveDown'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('moveDown', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-down') . '</a>';
                    } else {
                        $cells['moveDown'] = $this->spaceIcon;
                    }
                } elseif (!$this->table) {
                    $cells['moveUp'] = $this->spaceIcon;
                    $cells['moveDown'] = $this->spaceIcon;
                }
                // "Hide/Unhide" links:
                $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
                if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $hiddenField))) {
                    if ($row[$hiddenField]) {
                        $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
                        $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('unHide' . ($table == 'pages' ? 'Page' : ''), TRUE) . '">' . IconUtility::getSpriteIcon('actions-edit-unhide') . '</a>';
                    } else {
                        $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
                        $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('hide' . ($table == 'pages' ? 'Page' : ''), TRUE) . '">' . IconUtility::getSpriteIcon('actions-edit-hide') . '</a>';
                    }
                } elseif (!$this->table) {
                    $cells['hide'] = $this->spaceIcon;
                }
                // "Delete" link:
                if ($table == 'pages' && $localCalcPerms & 4 || $table != 'pages' && $this->calcPerms & 16) {
                    // Check if the record version is in "deleted" state, because that will switch the action to "restore"
                    if ($GLOBALS['BE_USER']->workspace > 0 && isset($row['t3ver_state']) && (int) $row['t3ver_state'] === 2) {
                        $actionName = 'restore';
                        $refCountMsg = '';
                    } else {
                        $actionName = 'delete';
                        $refCountMsg = BackendUtility::referenceCount($table, $row['uid'], ' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToRecord'), $this->getReferenceCount($table, $row['uid'])) . BackendUtility::translationCount($table, $row['uid'], ' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord'));
                    }
                    $titleOrig = BackendUtility::getRecordTitle($table, $row, FALSE, TRUE);
                    $title = GeneralUtility::slashJS(GeneralUtility::fixed_lgd_cs($titleOrig, $this->fixedL), 1);
                    $warningText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->getLL($actionName . 'Warning') . ' "' . $title . '" ' . $refCountMsg);
                    $params = '&cmd[' . $table . '][' . $row['uid'] . '][delete]=1';
                    $onClick = htmlspecialchars('if (confirm(' . $warningText . ')) {jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');} return false;');
                    $icon = IconUtility::getSpriteIcon('actions-edit-' . $actionName);
                    $linkTitle = $GLOBALS['LANG']->getLL($actionName, TRUE);
                    $cells['delete'] = '<a href="#" onclick="' . $onClick . '" title="' . $linkTitle . '">' . $icon . '</a>';
                } elseif (!$this->table) {
                    $cells['delete'] = $this->spaceIcon;
                }
                // "Levels" links: Moving pages into new levels...
                if ($permsEdit && $table == 'pages' && !$this->searchLevels) {
                    // Up (Paste as the page right after the current parent page)
                    if ($this->calcPerms & 8) {
                        $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . -$this->id;
                        $cells['moveLeft'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('prevLevel', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-left') . '</a>';
                    }
                    // Down (Paste as subpage to the page right above)
                    if ($this->currentTable['prevUid'][$row['uid']]) {
                        $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']]));
                        if ($localCalcPerms & 8) {
                            $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
                            $cells['moveRight'] = '<a href="#" onclick="' . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');') . '" title="' . $GLOBALS['LANG']->getLL('nextLevel', TRUE) . '">' . IconUtility::getSpriteIcon('actions-move-right') . '</a>';
                        } else {
                            $cells['moveRight'] = $this->spaceIcon;
                        }
                    } else {
                        $cells['moveRight'] = $this->spaceIcon;
                    }
                } elseif (!$this->table) {
                    $cells['moveLeft'] = $this->spaceIcon;
                    $cells['moveRight'] = $this->spaceIcon;
                }
            }
        }
        /**
         * @hook recStatInfoHooks: Allows to insert HTML before record icons on various places
         * @date 2007-09-22
         * @request Kasper Skårhøj <*****@*****.**>
         */
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
            $stat = '';
            $_params = array($table, $row['uid']);
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
                $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
            }
            $cells['stat'] = $stat;
        }
        /**
         * @hook makeControl: Allows to change control icons of records in list-module
         * @date 2007-11-20
         * @request Bernhard Kraft <*****@*****.**>
         * @usage This hook method gets passed the current $cells array as third parameter. This array contains values for the icons/actions generated for each record in Web>List. Each array entry is accessible by an index-key. The order of the icons is dependend on the order of those array entries.
         */
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
                $hookObject = GeneralUtility::getUserObj($classData);
                if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
                    throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567840);
                }
                $cells = $hookObject->makeControl($table, $row, $cells, $this);
            }
        }
        // Compile items into a DIV-element:
        return '
											<!-- CONTROL PANEL: ' . $table . ':' . $row['uid'] . ' -->
											<div class="typo3-DBctrl">' . implode('', $cells) . '</div>';
    }
Beispiel #12
0
 /**
  * Recursive traversal of page tree
  *
  * @param int $pageId Page root id
  * @param int $depth Depth
  * @param array $dirtyFlexFormFields the list of all previously found flexform fields
  * @return array
  */
 protected function findAllDirtyFlexformsInPage(int $pageId, int $depth, array $dirtyFlexFormFields = []) : array
 {
     if ($pageId > 0) {
         $dirtyFlexFormFields = $this->compareAllFlexFormsInRecord('pages', $pageId, $dirtyFlexFormFields);
     }
     // Traverse tables of records that belongs to this page
     foreach ($GLOBALS['TCA'] as $tableName => $tableConfiguration) {
         if ($tableName !== 'pages') {
             // Select all records belonging to page:
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
             $queryBuilder->getRestrictions()->removeAll();
             $result = $queryBuilder->select('uid')->from($tableName)->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)))->execute();
             while ($rowSub = $result->fetch()) {
                 // Traverse flexforms
                 $dirtyFlexFormFields = $this->compareAllFlexFormsInRecord($tableName, $rowSub['uid'], $dirtyFlexFormFields);
                 // Add any versions of those records
                 $versions = BackendUtility::selectVersionsOfRecord($tableName, $rowSub['uid'], 'uid,t3ver_wsid,t3ver_count', null, true);
                 if (is_array($versions)) {
                     foreach ($versions as $verRec) {
                         if (!$verRec['_CURRENT_VERSION']) {
                             // Traverse flexforms
                             $dirtyFlexFormFields = $this->compareAllFlexFormsInRecord($tableName, $verRec['uid'], $dirtyFlexFormFields);
                         }
                     }
                 }
             }
         }
     }
     // Find subpages
     if ($depth > 0) {
         $depth--;
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         $queryBuilder->getRestrictions()->removeAll();
         $result = $queryBuilder->select('uid')->from('pages')->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)))->orderBy('sorting')->execute();
         while ($row = $result->fetch()) {
             $dirtyFlexFormFields = $this->findAllDirtyFlexformsInPage($row['uid'], $depth, $dirtyFlexFormFields);
         }
     }
     // Add any versions of pages
     if ($pageId > 0) {
         $versions = BackendUtility::selectVersionsOfRecord('pages', $pageId, 'uid,t3ver_oid,t3ver_wsid,t3ver_count', null, true);
         if (is_array($versions)) {
             foreach ($versions as $verRec) {
                 if (!$verRec['_CURRENT_VERSION']) {
                     $dirtyFlexFormFields = $this->findAllDirtyFlexformsInPage($verRec['uid'], $depth, $dirtyFlexFormFields);
                 }
             }
         }
     }
     return $dirtyFlexFormFields;
 }
Beispiel #13
0
 /**
  * Find orphan records
  * VERY CPU and memory intensive since it will look up the whole page tree!
  *
  * @return array
  */
 public function main()
 {
     // Initialize result array:
     $resultArray = ['message' => $this->cli_help['name'] . LF . LF . $this->cli_help['description'], 'headers' => ['versions' => ['All versions', 'Showing all versions of records found', 0], 'versions_published' => ['All published versions', 'This is all records that has been published and can therefore be removed permanently', 1], 'versions_liveWS' => ['All versions in Live workspace', 'This is all records that are offline versions in the Live workspace. You may wish to flush these if you only use workspaces for versioning since then you might find lots of versions piling up in the live workspace which have simply been disconnected from the workspace before they were published.', 1], 'versions_lost_workspace' => ['Versions outside a workspace', 'Versions that has lost their connection to a workspace in TYPO3.', 3], 'versions_inside_versioned_page' => ['Versions in versions', 'Versions inside an already versioned page. Something that is confusing to users and therefore should not happen but is technically possible.', 2], 'versions_unused_placeholders' => ['Unused placeholder records', 'Placeholder records which are not used anymore by offline versions.', 2], 'versions_move_placeholders_ok' => ['Move placeholders', 'Move-to placeholder records which has good integrity', 0], 'versions_move_placeholders_bad' => ['Move placeholders with bad integrity', 'Move-to placeholder records which has bad integrity', 2], 'versions_move_id_check' => ['Checking if t3ver_move_id is correct', 't3ver_move_id must only be set with online records having t3ver_state=3.', 2]], 'versions' => []];
     $startingPoint = $this->cli_isArg('--pid') ? MathUtility::forceIntegerInRange($this->cli_argValue('--pid'), 0) : 0;
     $depth = $this->cli_isArg('--depth') ? MathUtility::forceIntegerInRange($this->cli_argValue('--depth'), 0) : 1000;
     $this->genTree($startingPoint, $depth, (int) $this->cli_argValue('--echotree'));
     $resultArray['versions'] = $this->recStats['versions'];
     $resultArray['versions_published'] = $this->recStats['versions_published'];
     $resultArray['versions_liveWS'] = $this->recStats['versions_liveWS'];
     $resultArray['versions_lost_workspace'] = $this->recStats['versions_lost_workspace'];
     $resultArray['versions_inside_versioned_page'] = $this->recStats['versions_inside_versioned_page'];
     // Finding all placeholders with no records attached!
     $resultArray['versions_unused_placeholders'] = [];
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if ($cfg['ctrl']['versioningWS']) {
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
             $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
             $result = $queryBuilder->select('uid', 'pid')->from($table)->where($queryBuilder->expr()->gte('pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)), $queryBuilder->expr()->eq('t3ver_state', $queryBuilder->createNamedParameter((string) new VersionState(VersionState::NEW_PLACEHOLDER), \PDO::PARAM_INT)))->execute();
             while ($placeholderRecord = $result->fetch()) {
                 if (count(BackendUtility::selectVersionsOfRecord($table, $placeholderRecord['uid'], 'uid', '*', null)) <= 1) {
                     $resultArray['versions_unused_placeholders'][GeneralUtility::shortMD5($table . ':' . $placeholderRecord['uid'])] = $table . ':' . $placeholderRecord['uid'];
                 }
             }
         }
     }
     asort($resultArray['versions_unused_placeholders']);
     // Finding all move placeholders with inconsistencies:
     $resultArray['versions_move_placeholders_ok'] = [];
     $resultArray['versions_move_placeholders_bad'] = [];
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if (BackendUtility::isTableWorkspaceEnabled($table)) {
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
             $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
             $result = $queryBuilder->select('uid', 'pid', 't3ver_move_id', 't3ver_wsid', 't3ver_state')->from($table)->where($queryBuilder->expr()->gte('pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)), $queryBuilder->expr()->eq('t3ver_state', $queryBuilder->createNamedParameter((string) new VersionState(VersionState::MOVE_PLACEHOLDER), \PDO::PARAM_INT)))->execute();
             while ($placeholderRecord = $result->fetch()) {
                 $shortID = GeneralUtility::shortMD5($table . ':' . $placeholderRecord['uid']);
                 if ((int) $placeholderRecord['t3ver_wsid'] !== 0) {
                     $phrecCopy = $placeholderRecord;
                     if (BackendUtility::movePlhOL($table, $placeholderRecord)) {
                         if ($wsAlt = BackendUtility::getWorkspaceVersionOfRecord($phrecCopy['t3ver_wsid'], $table, $placeholderRecord['uid'], 'uid,pid,t3ver_state')) {
                             if (!VersionState::cast($wsAlt['t3ver_state'])->equals(VersionState::MOVE_POINTER)) {
                                 $resultArray['versions_move_placeholders_bad'][$shortID] = [$table . ':' . $placeholderRecord['uid'], 'State for version was not "4" as it should be!', $phrecCopy];
                             } else {
                                 $resultArray['versions_move_placeholders_ok'][$shortID] = [$table . ':' . $placeholderRecord['uid'], 'PLH' => $phrecCopy, 'online' => $placeholderRecord, 'PNT' => $wsAlt];
                             }
                         } else {
                             $resultArray['versions_move_placeholders_bad'][$shortID] = [$table . ':' . $placeholderRecord['uid'], 'No version was found for online record to be moved. A version must exist.', $phrecCopy];
                         }
                     } else {
                         $resultArray['versions_move_placeholders_bad'][$shortID] = [$table . ':' . $placeholderRecord['uid'], 'Did not find online record for "t3ver_move_id" value ' . $placeholderRecord['t3ver_move_id'], $placeholderRecord];
                     }
                 } else {
                     $resultArray['versions_move_placeholders_bad'][$shortID] = [$table . ':' . $placeholderRecord['uid'], 'Placeholder was not assigned a workspace value in t3ver_wsid.', $placeholderRecord];
                 }
             }
         }
     }
     ksort($resultArray['versions_move_placeholders_ok']);
     ksort($resultArray['versions_move_placeholders_bad']);
     // Finding move_id_check inconsistencies:
     $resultArray['versions_move_id_check'] = [];
     foreach ($GLOBALS['TCA'] as $table => $cfg) {
         if (BackendUtility::isTableWorkspaceEnabled($table)) {
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
             $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
             $result = $queryBuilder->select('uid', 'pid', 't3ver_move_id', 't3ver_wsid', 't3ver_state')->from($table)->where($queryBuilder->expr()->neq('t3ver_move_id', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)))->execute();
             while ($placeholderRecord = $result->fetch()) {
                 if (VersionState::cast($placeholderRecord['t3ver_state'])->equals(VersionState::MOVE_PLACEHOLDER)) {
                     if ($placeholderRecord['pid'] != -1) {
                     } else {
                         $resultArray['versions_move_id_check'][] = [$table . ':' . $placeholderRecord['uid'], 'Record was offline, must not be!', $placeholderRecord];
                     }
                 } else {
                     $resultArray['versions_move_id_check'][] = [$table . ':' . $placeholderRecord['uid'], 'Record had t3ver_move_id set to "' . $placeholderRecord['t3ver_move_id'] . '" while having t3ver_state=' . $placeholderRecord['t3ver_state'], $placeholderRecord];
                 }
             }
         }
     }
     return $resultArray;
 }