[TASK] Create own response instance in controller actions
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / Page / SortSubPagesController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Controller\Page;
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
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Template\ModuleTemplate;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
25 use TYPO3\CMS\Core\DataHandling\DataHandler;
26 use TYPO3\CMS\Core\Http\HtmlResponse;
27 use TYPO3\CMS\Core\Imaging\Icon;
28 use TYPO3\CMS\Core\Imaging\IconFactory;
29 use TYPO3\CMS\Core\Localization\LanguageService;
30 use TYPO3\CMS\Core\Type\Bitmask\Permission;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32 use TYPO3\CMS\Fluid\View\StandaloneView;
33
34 /**
35 * "Sort sub pages" controller - reachable from context menu "more" on page records
36 */
37 class SortSubPagesController
38 {
39 /**
40 * ModuleTemplate object
41 *
42 * @var ModuleTemplate
43 */
44 protected $moduleTemplate;
45
46 /**
47 * Constructor Method
48 *
49 * @var $moduleTemplate ModuleTemplate
50 */
51 public function __construct(ModuleTemplate $moduleTemplate = null)
52 {
53 $this->moduleTemplate = $moduleTemplate ?? GeneralUtility::makeInstance(ModuleTemplate::class);
54 }
55
56 /**
57 * Main function Handling input variables and rendering main view
58 *
59 * @param $request ServerRequestInterface
60 * @return ResponseInterface Response
61 */
62 public function mainAction(ServerRequestInterface $request): ResponseInterface
63 {
64 $backendUser = $this->getBackendUser();
65 $parentPageUid = (int)$request->getQueryParams()['id'];
66
67 // Show only if there is a valid page and if this page may be viewed by the user
68 $pageInformation = BackendUtility::readPageAccess($parentPageUid, $backendUser->getPagePermsClause(Permission::PAGE_SHOW));
69 if (!is_array($pageInformation)) {
70 // User has no permission on parent page, should not happen, just render an empty page
71 $this->moduleTemplate->setContent('');
72 return new HtmlResponse($this->moduleTemplate->renderContent());
73 }
74
75 // Doc header handling
76 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
77 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageInformation);
78 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
79 $cshButton = $buttonBar->makeHelpButton()
80 ->setModuleName('pages_sort')
81 ->setFieldName('pages_sort');
82 $viewButton = $buttonBar->makeLinkButton()
83 ->setOnClick(BackendUtility::viewOnClick($parentPageUid, '', BackendUtility::BEgetRootLine($parentPageUid)))
84 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
85 ->setIcon($iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL))
86 ->setHref('#');
87 $shortcutButton = $buttonBar->makeShortcutButton()
88 ->setModuleName('pages_sort')
89 ->setGetVariables(['id']);
90 $buttonBar->addButton($cshButton)->addButton($viewButton)->addButton($shortcutButton);
91
92 // Main view setup
93 $view = GeneralUtility::makeInstance(StandaloneView::class);
94 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
95 'EXT:backend/Resources/Private/Templates/Page/SortSubPages.html'
96 ));
97
98 $isInWorkspace = $backendUser->workspace !== 0;
99 $view->assign('isInWorkspace', $isInWorkspace);
100 $view->assign('maxTitleLength', $backendUser->uc['titleLen'] ?? 20);
101 $view->assign('parentPageUid', $parentPageUid);
102 $view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
103 $view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
104
105 if (!$isInWorkspace) {
106 // Apply new sorting if given
107 $newSortBy = $request->getQueryParams()['newSortBy'] ?? null;
108 if ($newSortBy && in_array($newSortBy, ['title', 'subtitle', 'crdate', 'tstamp'], true)) {
109 $this->sortSubPagesByField($parentPageUid, (string)$newSortBy);
110 } elseif ($newSortBy && $newSortBy === 'reverseCurrentSorting') {
111 $this->reverseSortingOfPages($parentPageUid);
112 }
113
114 // Get sub pages, loop through them and add page/user specific permission details
115 $pageRecords = $this->getSubPagesOfPage($parentPageUid);
116 $hasInvisiblePage = false;
117 $subPages = [];
118 foreach ($pageRecords as $page) {
119 $pageWithPermissions = [];
120 $pageWithPermissions['record'] = $page;
121 $calculatedPermissions = $backendUser->calcPerms($page);
122 $pageWithPermissions['canEdit'] = $backendUser->isAdmin() || $calculatedPermissions & Permission::PAGE_EDIT;
123 $canSeePage = $backendUser->isAdmin() || $calculatedPermissions & Permission::PAGE_SHOW;
124 if ($canSeePage) {
125 $subPages[] = $pageWithPermissions;
126 } else {
127 $hasInvisiblePage = true;
128 }
129 }
130 $view->assign('subPages', $subPages);
131 $view->assign('hasInvisiblePage', $hasInvisiblePage);
132 }
133
134 $this->moduleTemplate->setContent($view->render());
135 return new HtmlResponse($this->moduleTemplate->renderContent());
136 }
137
138 /**
139 * Sort sub pages of given uid by field name alphabetically
140 *
141 * @param int $parentPageUid Parent page uid
142 * @param string $newSortBy Field name to sort by
143 * @throws \RuntimeException If $newSortBy does not validate
144 */
145 protected function sortSubPagesByField(int $parentPageUid, string $newSortBy)
146 {
147 if (!in_array($newSortBy, ['title', 'subtitle', 'crdate', 'tstamp'], true)) {
148 throw new \RuntimeException(
149 'New sort by must be one of "title", "subtitle", "crdate" or tstamp',
150 1498924810
151 );
152 }
153 $subPages = $this->getSubPagesOfPage($parentPageUid, $newSortBy);
154 if (!empty($subPages)) {
155 $subPages = array_reverse($subPages);
156 $this->persistNewSubPageOrder($parentPageUid, $subPages);
157 }
158 }
159
160 /**
161 * Reverse current sorting of sub pages
162 *
163 * @param int $parentPageUid Parent page uid
164 */
165 protected function reverseSortingOfPages(int $parentPageUid)
166 {
167 $subPages = $this->getSubPagesOfPage($parentPageUid);
168 if (!empty($subPages)) {
169 $this->persistNewSubPageOrder($parentPageUid, $subPages);
170 }
171 }
172
173 /**
174 * Store new sub page order
175 *
176 * @param int $parentPageUid Parent page uid
177 * @param array $subPages List of sub pages in new order
178 */
179 protected function persistNewSubPageOrder(int $parentPageUid, array $subPages)
180 {
181 $commandArray = [];
182 foreach ($subPages as $subPage) {
183 $commandArray['pages'][$subPage['uid']]['move'] = $parentPageUid;
184 }
185 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
186 $dataHandler->start([], $commandArray);
187 $dataHandler->process_cmdmap();
188 BackendUtility::setUpdateSignal('updatePageTree');
189 }
190
191 /**
192 * Get a list of sub pages with some all fields from given page.
193 * Fetch all data fields for full page icon display
194 *
195 * @param int $parentPageUid Get sub pages from this pages
196 * @param string $orderBy Order pages by this field
197 * @return array
198 */
199 protected function getSubPagesOfPage(int $parentPageUid, string $orderBy = 'sorting'): array
200 {
201 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
202 $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
203 return $queryBuilder->select('*')
204 ->from('pages')
205 ->where(
206 $queryBuilder->expr()->eq(
207 'pid',
208 $queryBuilder->createNamedParameter($parentPageUid, \PDO::PARAM_INT)
209 )
210 )
211 ->orderBy($orderBy)
212 ->execute()
213 ->fetchAll();
214 }
215
216 /**
217 * Returns LanguageService
218 *
219 * @return LanguageService
220 */
221 protected function getLanguageService()
222 {
223 return $GLOBALS['LANG'];
224 }
225
226 /**
227 * Returns current BE user
228 *
229 * @return BackendUserAuthentication
230 */
231 protected function getBackendUser()
232 {
233 return $GLOBALS['BE_USER'];
234 }
235 }