1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18namespace TYPO3\CMS\Backend\Controller\ContentElement; 19 20use Psr\Http\Message\ResponseInterface; 21use Psr\Http\Message\ServerRequestInterface; 22use TYPO3\CMS\Backend\Template\ModuleTemplate; 23use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; 24use TYPO3\CMS\Backend\Tree\View\ContentMovingPagePositionMap; 25use TYPO3\CMS\Backend\Tree\View\PageMovingPagePositionMap; 26use TYPO3\CMS\Backend\Utility\BackendUtility; 27use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; 28use TYPO3\CMS\Core\Http\HtmlResponse; 29use TYPO3\CMS\Core\Imaging\Icon; 30use TYPO3\CMS\Core\Imaging\IconFactory; 31use TYPO3\CMS\Core\Localization\LanguageService; 32use TYPO3\CMS\Core\Page\PageRenderer; 33use TYPO3\CMS\Core\Type\Bitmask\Permission; 34use TYPO3\CMS\Core\Utility\GeneralUtility; 35use TYPO3\CMS\Fluid\View\StandaloneView; 36 37/** 38 * Script Class for rendering the move-element wizard display 39 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API. 40 */ 41class MoveElementController 42{ 43 protected int $sys_language = 0; 44 protected int $page_id = 0; 45 protected string $table = ''; 46 protected string $R_URI = ''; 47 protected int $moveUid = 0; 48 protected int $makeCopy = 0; 49 protected string $perms_clause = ''; 50 51 protected ?ModuleTemplate $moduleTemplate = null; 52 53 protected IconFactory $iconFactory; 54 protected PageRenderer $pageRenderer; 55 protected ModuleTemplateFactory $moduleTemplateFactory; 56 57 public function __construct( 58 IconFactory $iconFactory, 59 PageRenderer $pageRenderer, 60 ModuleTemplateFactory $moduleTemplateFactory 61 ) { 62 $this->iconFactory = $iconFactory; 63 $this->pageRenderer = $pageRenderer; 64 $this->moduleTemplateFactory = $moduleTemplateFactory; 65 } 66 67 public function mainAction(ServerRequestInterface $request): ResponseInterface 68 { 69 $this->moduleTemplate = $this->moduleTemplateFactory->create($request); 70 $parsedBody = $request->getParsedBody(); 71 $queryParams = $request->getQueryParams(); 72 73 $this->sys_language = (int)($parsedBody['sys_language'] ?? $queryParams['sys_language'] ?? 0); 74 $this->page_id = (int)($parsedBody['uid'] ?? $queryParams['uid'] ?? 0); 75 $this->table = (string)($parsedBody['table'] ?? $queryParams['table'] ?? ''); 76 $this->R_URI = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? ''); 77 $this->moveUid = (int)(($parsedBody['moveUid'] ?? $queryParams['moveUid'] ?? false) ?: $this->page_id); 78 $this->makeCopy = (int)($parsedBody['makeCopy'] ?? $queryParams['makeCopy'] ?? 0); 79 // Select-pages where clause for read-access 80 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW); 81 82 // Setting up the buttons and markers for docheader 83 $this->getButtons(); 84 // Build the <body> for the module 85 $this->moduleTemplate->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_misc.xlf:movingElement')); 86 $this->moduleTemplate->setContent($this->renderContent()); 87 return new HtmlResponse($this->moduleTemplate->renderContent()); 88 } 89 90 /** 91 * Creating the module output. 92 */ 93 protected function renderContent(): string 94 { 95 if (!$this->page_id) { 96 return ''; 97 } 98 $assigns = []; 99 $backendUser = $this->getBackendUser(); 100 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip'); 101 // Get record for element: 102 $elRow = BackendUtility::getRecordWSOL($this->table, $this->moveUid); 103 // Headerline: Icon, record title: 104 $assigns['table'] = $this->table; 105 $assigns['elRow'] = $elRow; 106 $assigns['recordTooltip'] = BackendUtility::getRecordToolTip($elRow, $this->table); 107 $assigns['recordTitle'] = BackendUtility::getRecordTitle($this->table, $elRow, true); 108 // Make-copy checkbox (clicking this will reload the page with the GET var makeCopy set differently): 109 $assigns['makeCopyChecked'] = (bool)$this->makeCopy; 110 $assigns['makeCopyUrl'] = GeneralUtility::linkThisScript(['makeCopy' => !$this->makeCopy]); 111 // Get page record (if accessible): 112 if ($this->table !== 'pages' && $this->moveUid === $this->page_id) { 113 $this->page_id = (int)$elRow['pid']; 114 } 115 $pageInfo = BackendUtility::readPageAccess($this->page_id, $this->perms_clause); 116 $assigns['pageInfo'] = $pageInfo; 117 if (is_array($pageInfo) && $backendUser->isInWebMount($pageInfo['pid'], $this->perms_clause)) { 118 // Initialize the page position map: 119 $pagePositionMap = GeneralUtility::makeInstance(PageMovingPagePositionMap::class); 120 $pagePositionMap->moveOrCopy = $this->makeCopy ? 'copy' : 'move'; 121 $pagePositionMap->moveUid = $this->moveUid; 122 switch ($this->table) { 123 case 'pages': 124 // Print a "go-up" link IF there is a real parent page (and if the user has read-access to that page). 125 if ($pageInfo['pid']) { 126 $pidPageInfo = BackendUtility::readPageAccess($pageInfo['pid'], $this->perms_clause); 127 if (is_array($pidPageInfo)) { 128 if ($backendUser->isInWebMount($pidPageInfo['pid'], $this->perms_clause)) { 129 $assigns['goUpUrl'] = GeneralUtility::linkThisScript([ 130 'uid' => (int)$pageInfo['pid'], 131 'moveUid' => $this->moveUid, 132 ]); 133 } else { 134 $assigns['pidPageInfo'] = $pidPageInfo; 135 } 136 $assigns['pidRecordTitle'] = BackendUtility::getRecordTitle('pages', $pidPageInfo, true); 137 } 138 } 139 // Create the position tree: 140 $assigns['positionTree'] = $pagePositionMap->positionTree($this->page_id, $pageInfo, $this->perms_clause, $this->R_URI); 141 break; 142 case 'tt_content': 143 // Initialize the content position map: 144 $contentPositionMap = GeneralUtility::makeInstance(ContentMovingPagePositionMap::class); 145 $contentPositionMap->copyMode = $this->makeCopy ? 'copy' : 'move'; 146 $contentPositionMap->moveUid = $this->moveUid; 147 $contentPositionMap->cur_sys_language = $this->sys_language; 148 $contentPositionMap->R_URI = $this->R_URI; 149 // Headerline for the parent page: Icon, record title: 150 $assigns['ttContent']['recordTooltip'] = BackendUtility::getRecordToolTip($pageInfo); 151 $assigns['ttContent']['recordTitle'] = BackendUtility::getRecordTitle('pages', $pageInfo, true); 152 // Adding parent page-header and the content element columns from position-map: 153 $assigns['contentElementColumns'] = $contentPositionMap->printContentElementColumns($this->page_id); 154 // Print a "go-up" link IF there is a real parent page (and if the user has read-access to that page). 155 if ($pageInfo['pid'] > 0) { 156 $pidPageInfo = BackendUtility::readPageAccess($pageInfo['pid'], $this->perms_clause); 157 if (is_array($pidPageInfo)) { 158 if ($backendUser->isInWebMount($pidPageInfo['pid'], $this->perms_clause)) { 159 $assigns['goUpUrl'] = GeneralUtility::linkThisScript([ 160 'uid' => (int)$pageInfo['pid'], 161 'moveUid' => $this->moveUid, 162 ]); 163 } else { 164 $assigns['pidPageInfo'] = $pidPageInfo; 165 } 166 $assigns['pidRecordTitle'] = BackendUtility::getRecordTitle('pages', $pidPageInfo, true); 167 } 168 } 169 // Create the position tree (for pages) without insert lines: 170 $pagePositionMap->dontPrintPageInsertIcons = 1; 171 $assigns['positionTree'] = $pagePositionMap->positionTree($this->page_id, $pageInfo, $this->perms_clause, $this->R_URI); 172 } 173 } 174 175 // Rendering of the output via fluid 176 $view = $this->initializeView(); 177 $view->assignMultiple($assigns); 178 return $view->render(); 179 } 180 181 protected function initializeView(): StandaloneView 182 { 183 $view = GeneralUtility::makeInstance(StandaloneView::class); 184 $view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates']); 185 $view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials']); 186 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName( 187 'EXT:backend/Resources/Private/Templates/ContentElement/MoveElement.html' 188 )); 189 return $view; 190 } 191 192 /** 193 * Create the panel of buttons for submitting the form or otherwise perform operations. 194 */ 195 protected function getButtons() 196 { 197 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar(); 198 if ($this->page_id) { 199 if ($this->table === 'pages') { 200 $cshButton = $buttonBar->makeHelpButton() 201 ->setModuleName('xMOD_csh_corebe') 202 ->setFieldName('move_el_pages'); 203 $buttonBar->addButton($cshButton); 204 } elseif ($this->table === 'tt_content') { 205 $cshButton = $buttonBar->makeHelpButton() 206 ->setModuleName('xMOD_csh_corebe') 207 ->setFieldName('move_el_cs'); 208 $buttonBar->addButton($cshButton); 209 } 210 211 if ($this->R_URI) { 212 $backButton = $buttonBar->makeLinkButton() 213 ->setHref($this->R_URI) 214 ->setShowLabelText(true) 215 ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_misc.xlf:goBack')) 216 ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)); 217 $buttonBar->addButton($backButton); 218 } 219 } 220 } 221 222 protected function getLanguageService(): LanguageService 223 { 224 return $GLOBALS['LANG']; 225 } 226 227 protected function getBackendUser(): BackendUserAuthentication 228 { 229 return $GLOBALS['BE_USER']; 230 } 231} 232