[!!!][TASK] Remove deprecated code from EXT:recordlist
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / Controller / RecordListController.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Clipboard\Clipboard;
20 use TYPO3\CMS\Backend\Routing\UriBuilder;
21 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
22 use TYPO3\CMS\Backend\Template\ModuleTemplate;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
25 use TYPO3\CMS\Core\Database\ConnectionPool;
26 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
27 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28 use TYPO3\CMS\Core\DataHandling\DataHandler;
29 use TYPO3\CMS\Core\Http\HtmlResponse;
30 use TYPO3\CMS\Core\Imaging\Icon;
31 use TYPO3\CMS\Core\Imaging\IconFactory;
32 use TYPO3\CMS\Core\Localization\LanguageService;
33 use TYPO3\CMS\Core\Messaging\FlashMessage;
34 use TYPO3\CMS\Core\Messaging\FlashMessageService;
35 use TYPO3\CMS\Core\Page\PageRenderer;
36 use TYPO3\CMS\Core\Site\Entity\SiteInterface;
37 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
38 use TYPO3\CMS\Core\Type\Bitmask\Permission;
39 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
40 use TYPO3\CMS\Core\Utility\GeneralUtility;
41 use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
42
43 /**
44 * Script Class for the Web > List module; rendering the listing of records on a page
45 * @internal This class is a specific Backend controller implementation and is not part of the TYPO3's Core API.
46 */
47 class RecordListController
48 {
49 /**
50 * Page Id for which to make the listing
51 *
52 * @var int
53 */
54 protected $id;
55
56 /**
57 * Pointer - for browsing list of records.
58 *
59 * @var int
60 */
61 protected $pointer;
62
63 /**
64 * Which table to make extended listing for
65 *
66 * @var string
67 */
68 protected $table;
69
70 /**
71 * Search-fields
72 *
73 * @var string
74 */
75 protected $search_field;
76
77 /**
78 * Search-levels
79 *
80 * @var int
81 */
82 protected $search_levels;
83
84 /**
85 * Show-limit
86 *
87 * @var int
88 */
89 protected $showLimit;
90
91 /**
92 * Return URL
93 *
94 * @var string
95 */
96 protected $returnUrl;
97
98 /**
99 * Clear-cache flag - if set, clears page cache for current id.
100 *
101 * @var bool
102 */
103 protected $clear_cache;
104
105 /**
106 * Command: Eg. "delete" or "setCB" (for DataHandler / clipboard operations)
107 *
108 * @var string
109 */
110 protected $cmd;
111
112 /**
113 * Table on which the cmd-action is performed.
114 *
115 * @var string
116 */
117 protected $cmd_table;
118
119 /**
120 * Page select perms clause
121 *
122 * @var int
123 */
124 protected $perms_clause;
125
126 /**
127 * Module TSconfig
128 *
129 * @var array
130 * @internal Still used by DatabaseRecordList via $GLOBALS['SOBE']
131 */
132 public $modTSconfig;
133
134 /**
135 * Current ids page record
136 *
137 * @var mixed[]|bool
138 */
139 protected $pageinfo;
140
141 /**
142 * Menu configuration
143 *
144 * @var string[]
145 */
146 protected $MOD_MENU = [];
147
148 /**
149 * Module settings (session variable)
150 *
151 * @var string[]
152 * @internal Still used by DatabaseRecordList via $GLOBALS['SOBE']
153 */
154 public $MOD_SETTINGS = [];
155
156 /**
157 * Module output accumulation
158 *
159 * @var string
160 */
161 protected $content;
162
163 /**
164 * @var string
165 */
166 protected $body = '';
167
168 /**
169 * @var PageRenderer
170 */
171 protected $pageRenderer;
172
173 /**
174 * @var IconFactory
175 */
176 protected $iconFactory;
177
178 /**
179 * ModuleTemplate object
180 *
181 * @var ModuleTemplate
182 */
183 protected $moduleTemplate;
184
185 /**
186 * @var SiteInterface
187 */
188 protected $site;
189
190 /**
191 * @var SiteLanguage[]
192 */
193 protected $siteLanguages = [];
194
195 /**
196 * Constructor
197 */
198 public function __construct()
199 {
200 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
201 $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
202 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Recordlist/FieldSelectBox');
203 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Recordlist/Recordlist');
204 }
205
206 /**
207 * Initializing the module
208 */
209 protected function init()
210 {
211 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
212 $backendUser = $this->getBackendUserAuthentication();
213 $this->perms_clause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW);
214 // Get session data
215 $sessionData = $backendUser->getSessionData(__CLASS__);
216 $this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
217 // GPvars:
218 $this->id = (int)GeneralUtility::_GP('id');
219 $this->pointer = GeneralUtility::_GP('pointer');
220 $this->table = GeneralUtility::_GP('table');
221 $this->search_field = GeneralUtility::_GP('search_field');
222 $this->search_levels = (int)GeneralUtility::_GP('search_levels');
223 $this->showLimit = GeneralUtility::_GP('showLimit');
224 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
225 $this->clear_cache = GeneralUtility::_GP('clear_cache');
226 $this->cmd = GeneralUtility::_GP('cmd');
227 $this->cmd_table = GeneralUtility::_GP('cmd_table');
228 $sessionData['search_field'] = $this->search_field;
229 // Initialize menu
230 $this->menuConfig();
231 // Store session data
232 $backendUser->setAndSaveSessionData(self::class, $sessionData);
233 $this->getPageRenderer()->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
234 }
235
236 /**
237 * Initialize function menu array
238 */
239 protected function menuConfig()
240 {
241 // MENU-ITEMS:
242 $this->MOD_MENU = [
243 'bigControlPanel' => '',
244 'clipBoard' => '',
245 ];
246 // Loading module configuration:
247 $this->modTSconfig['properties'] = BackendUtility::getPagesTSconfig($this->id)['mod.']['web_list.'] ?? [];
248 // Clean up settings:
249 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), 'web_list');
250 }
251
252 /**
253 * Clears page cache for the current id, $this->id
254 */
255 protected function clearCache()
256 {
257 if ($this->clear_cache) {
258 $tce = GeneralUtility::makeInstance(DataHandler::class);
259 $tce->start([], []);
260 $tce->clear_cacheCmd($this->id);
261 }
262 }
263
264 /**
265 * Main function, starting the rendering of the list.
266 *
267 * @param ServerRequestInterface $request
268 */
269 protected function main(ServerRequestInterface $request)
270 {
271 $backendUser = $this->getBackendUserAuthentication();
272 $lang = $this->getLanguageService();
273 // Loading current page record and checking access:
274 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
275 $access = is_array($this->pageinfo);
276
277 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
278 $calcPerms = $backendUser->calcPerms($this->pageinfo);
279 $userCanEditPage = $calcPerms & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0);
280 if ($userCanEditPage) {
281 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', 'function(PageActions) {
282 PageActions.setPageId(' . (int)$this->id . ');
283 }');
284 }
285 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Recordlist/Tooltip');
286 // Apply predefined values for hidden checkboxes
287 // Set predefined value for DisplayBigControlPanel:
288 if ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'activated') {
289 $this->MOD_SETTINGS['bigControlPanel'] = true;
290 } elseif ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'deactivated') {
291 $this->MOD_SETTINGS['bigControlPanel'] = false;
292 }
293 // Set predefined value for Clipboard:
294 if ($this->modTSconfig['properties']['enableClipBoard'] === 'activated') {
295 $this->MOD_SETTINGS['clipBoard'] = true;
296 } elseif ($this->modTSconfig['properties']['enableClipBoard'] === 'deactivated') {
297 $this->MOD_SETTINGS['clipBoard'] = false;
298 } else {
299 if ($this->MOD_SETTINGS['clipBoard'] === null) {
300 $this->MOD_SETTINGS['clipBoard'] = true;
301 }
302 }
303
304 // Initialize the dblist object:
305 $dblist = GeneralUtility::makeInstance(DatabaseRecordList::class);
306 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
307 $dblist->script = (string)$uriBuilder->buildUriFromRoute('web_list');
308 $dblist->calcPerms = $calcPerms;
309 $dblist->thumbs = $backendUser->uc['thumbnailsByDefault'];
310 $dblist->returnUrl = $this->returnUrl;
311 $dblist->allFields = $this->MOD_SETTINGS['bigControlPanel'] || $this->table ? 1 : 0;
312 $dblist->showClipboard = 1;
313 $dblist->disableSingleTableView = $this->modTSconfig['properties']['disableSingleTableView'];
314 $dblist->listOnlyInSingleTableMode = $this->modTSconfig['properties']['listOnlyInSingleTableView'];
315 $dblist->hideTables = $this->modTSconfig['properties']['hideTables'];
316 $dblist->hideTranslations = $this->modTSconfig['properties']['hideTranslations'];
317 $dblist->tableTSconfigOverTCA = $this->modTSconfig['properties']['table.'];
318 $dblist->allowedNewTables = GeneralUtility::trimExplode(',', $this->modTSconfig['properties']['allowedNewTables'], true);
319 $dblist->deniedNewTables = GeneralUtility::trimExplode(',', $this->modTSconfig['properties']['deniedNewTables'], true);
320 $dblist->pageRow = $this->pageinfo;
321 $dblist->counter++;
322 $dblist->MOD_MENU = ['bigControlPanel' => '', 'clipBoard' => ''];
323 $dblist->modTSconfig = $this->modTSconfig;
324 $clickTitleMode = trim($this->modTSconfig['properties']['clickTitleMode']);
325 $dblist->clickTitleMode = $clickTitleMode === '' ? 'edit' : $clickTitleMode;
326 if (isset($this->modTSconfig['properties']['tableDisplayOrder.'])) {
327 $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
328 $dblist->setTableDisplayOrder($typoScriptService->convertTypoScriptArrayToPlainArray($this->modTSconfig['properties']['tableDisplayOrder.']));
329 }
330 // Clipboard is initialized:
331 // Start clipboard
332 $dblist->clipObj = GeneralUtility::makeInstance(Clipboard::class);
333 // Initialize - reads the clipboard content from the user session
334 $dblist->clipObj->initializeClipboard();
335 // Clipboard actions are handled:
336 // CB is the clipboard command array
337 $CB = GeneralUtility::_GET('CB');
338 if ($this->cmd === 'setCB') {
339 // CBH is all the fields selected for the clipboard, CBC is the checkbox fields which were checked.
340 // By merging we get a full array of checked/unchecked elements
341 // This is set to the 'el' array of the CB after being parsed so only the table in question is registered.
342 $CB['el'] = $dblist->clipObj->cleanUpCBC(array_merge(GeneralUtility::_POST('CBH'), (array)GeneralUtility::_POST('CBC')), $this->cmd_table);
343 }
344 if (!$this->MOD_SETTINGS['clipBoard']) {
345 // If the clipboard is NOT shown, set the pad to 'normal'.
346 $CB['setP'] = 'normal';
347 }
348 // Execute commands.
349 $dblist->clipObj->setCmd($CB);
350 // Clean up pad
351 $dblist->clipObj->cleanCurrent();
352 // Save the clipboard content
353 $dblist->clipObj->endClipboard();
354 // This flag will prevent the clipboard panel in being shown.
355 // It is set, if the clickmenu-layer is active AND the extended view is not enabled.
356 $dblist->dontShowClipControlPanels = ($dblist->clipObj->current === 'normal' && !$this->modTSconfig['properties']['showClipControlPanelsDespiteOfCMlayers']);
357 // If there is access to the page or root page is used for searching, then render the list contents and set up the document template object:
358 if ($access || ($this->id === 0 && $this->search_levels !== 0 && $this->search_field !== '')) {
359 // Deleting records...:
360 // Has not to do with the clipboard but is simply the delete action. The clipboard object is used to clean up the submitted entries to only the selected table.
361 if ($this->cmd === 'delete') {
362 $items = $dblist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), $this->cmd_table, 1);
363 if (!empty($items)) {
364 $cmd = [];
365 foreach ($items as $iK => $value) {
366 $iKParts = explode('|', $iK);
367 $cmd[$iKParts[0]][$iKParts[1]]['delete'] = 1;
368 }
369 $tce = GeneralUtility::makeInstance(DataHandler::class);
370 $tce->start([], $cmd);
371 $tce->process_cmdmap();
372 if (isset($cmd['pages'])) {
373 BackendUtility::setUpdateSignal('updatePageTree');
374 }
375 $tce->printLogErrorMessages();
376 }
377 }
378 // Initialize the listing object, dblist, for rendering the list:
379 $this->pointer = max(0, (int)$this->pointer);
380 $dblist->start($this->id, $this->table, $this->pointer, $this->search_field, $this->search_levels, $this->showLimit);
381 $dblist->setDispFields();
382 // Render the list of tables:
383 $dblist->generateList();
384 $listUrl = $dblist->listURL();
385 // Add JavaScript functions to the page:
386
387 $this->moduleTemplate->addJavaScriptCode(
388 'RecordListInlineJS',
389 '
390 function jumpExt(URL,anchor) {
391 var anc = anchor?anchor:"";
392 window.location.href = URL+(T3_THIS_LOCATION?"&returnUrl="+T3_THIS_LOCATION:"")+anc;
393 return false;
394 }
395 function jumpSelf(URL) {
396 window.location.href = URL+(T3_RETURN_URL?"&returnUrl="+T3_RETURN_URL:"");
397 return false;
398 }
399 function jumpToUrl(URL) {
400 window.location.href = URL;
401 return false;
402 }
403
404 function setHighlight(id) {
405 top.fsMod.recentIds["web"] = id;
406 top.fsMod.navFrameHighlightedID["web"] = top.fsMod.currentBank + "_" + id; // For highlighting
407
408 if (top.nav_frame && top.nav_frame.refresh_nav) {
409 top.nav_frame.refresh_nav();
410 }
411 }
412 ' . $this->moduleTemplate->redirectUrls($listUrl) . '
413 ' . $dblist->CBfunctions() . '
414 function editRecords(table,idList,addParams,CBflag) {
415 window.location.href="' . (string)$uriBuilder->buildUriFromRoute('record_edit', ['returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]) . '&edit["+table+"]["+idList+"]=edit"+addParams;
416 }
417 function editList(table,idList) {
418 var list="";
419
420 // Checking how many is checked, how many is not
421 var pointer=0;
422 var pos = idList.indexOf(",");
423 while (pos!=-1) {
424 if (cbValue(table+"|"+idList.substr(pointer,pos-pointer))) {
425 list+=idList.substr(pointer,pos-pointer)+",";
426 }
427 pointer=pos+1;
428 pos = idList.indexOf(",",pointer);
429 }
430 if (cbValue(table+"|"+idList.substr(pointer))) {
431 list+=idList.substr(pointer)+",";
432 }
433
434 return list ? list : idList;
435 }
436
437 if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
438 '
439 );
440
441 // Setting up the context sensitive menu:
442 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
443 }
444 // access
445 // Begin to compile the whole page, starting out with page header:
446 if (!$this->id) {
447 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
448 } else {
449 $title = $this->pageinfo['title'];
450 }
451 $this->body = $this->moduleTemplate->header($title);
452
453 // Additional header content
454 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['recordlist/Modules/Recordlist/index.php']['drawHeaderHook'] ?? [] as $hook) {
455 $params = [
456 'request' => $request,
457 ];
458 $null = null;
459 $this->body .= GeneralUtility::callUserFunction($hook, $params, $null);
460 }
461
462 $this->moduleTemplate->setTitle($title);
463
464 $output = '';
465 // Show the selector to add page translations and the list of translations of the current page
466 // but only when in "default" mode
467 if ($this->id && !$dblist->csvOutput && !$this->search_field && !$this->cmd && !$this->table) {
468 $output .= $this->languageSelector($this->id);
469 $pageTranslationsDatabaseRecordList = clone $dblist;
470 $pageTranslationsDatabaseRecordList->listOnlyInSingleTableMode = false;
471 $pageTranslationsDatabaseRecordList->disableSingleTableView = true;
472 $pageTranslationsDatabaseRecordList->deniedNewTables = ['pages'];
473 $pageTranslationsDatabaseRecordList->hideTranslations = '';
474 $pageTranslationsDatabaseRecordList->iLimit = $pageTranslationsDatabaseRecordList->itemsLimitPerTable;
475 $pageTranslationsDatabaseRecordList->showOnlyTranslatedRecords(true);
476 $output .= $pageTranslationsDatabaseRecordList->getTable('pages', $this->id);
477 }
478
479 if (!empty($dblist->HTMLcode)) {
480 $output .= $dblist->HTMLcode;
481 } else {
482 $flashMessage = GeneralUtility::makeInstance(
483 FlashMessage::class,
484 $lang->getLL('noRecordsOnThisPage'),
485 '',
486 FlashMessage::INFO
487 );
488 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
489 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
490 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue $defaultFlashMessageQueue */
491 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
492 $defaultFlashMessageQueue->enqueue($flashMessage);
493 }
494
495 $this->body .= '<form action="' . htmlspecialchars($dblist->listURL()) . '" method="post" name="dblistForm">';
496 $this->body .= $output;
497 $this->body .= '<input type="hidden" name="cmd_table" /><input type="hidden" name="cmd" /></form>';
498 // If a listing was produced, create the page footer with search form etc:
499 if ($dblist->HTMLcode) {
500 // Making field select box (when extended view for a single table is enabled):
501 if ($dblist->table) {
502 $this->body .= $dblist->fieldSelectBox($dblist->table);
503 }
504 // Adding checkbox options for extended listing and clipboard display:
505 $this->body .= '
506
507 <!--
508 Listing options for extended view and clipboard view
509 -->
510 <div class="typo3-listOptions">
511 <form action="" method="post">';
512
513 // Add "display bigControlPanel" checkbox:
514 if ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'selectable') {
515 $this->body .= '<div class="checkbox">' .
516 '<label for="checkLargeControl">' .
517 BackendUtility::getFuncCheck($this->id, 'SET[bigControlPanel]', $this->MOD_SETTINGS['bigControlPanel'], '', $this->table ? '&table=' . $this->table : '', 'id="checkLargeControl"') .
518 BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', htmlspecialchars($lang->getLL('largeControl'))) .
519 '</label>' .
520 '</div>';
521 }
522
523 // Add "clipboard" checkbox:
524 if ($this->modTSconfig['properties']['enableClipBoard'] === 'selectable') {
525 if ($dblist->showClipboard) {
526 $this->body .= '<div class="checkbox">' .
527 '<label for="checkShowClipBoard">' .
528 BackendUtility::getFuncCheck($this->id, 'SET[clipBoard]', $this->MOD_SETTINGS['clipBoard'], '', $this->table ? '&table=' . $this->table : '', 'id="checkShowClipBoard"') .
529 BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', htmlspecialchars($lang->getLL('showClipBoard'))) .
530 '</label>' .
531 '</div>';
532 }
533 }
534
535 $this->body .= '
536 </form>
537 </div>';
538 }
539 // Printing clipboard if enabled
540 if ($this->MOD_SETTINGS['clipBoard'] && $dblist->showClipboard && ($dblist->HTMLcode || $dblist->clipObj->hasElements())) {
541 $this->body .= '<div class="db_list-dashboard">' . $dblist->clipObj->printClipboard() . '</div>';
542 }
543 // Additional footer content
544 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['recordlist/Modules/Recordlist/index.php']['drawFooterHook'] ?? [] as $hook) {
545 $params = [
546 'request' => $request,
547 ];
548 $null = null;
549 $this->body .= GeneralUtility::callUserFunction($hook, $params, $null);
550 }
551 // Setting up the buttons for docheader
552 $dblist->getDocHeaderButtons($this->moduleTemplate);
553 // search box toolbar
554 if (!$this->modTSconfig['properties']['disableSearchBox'] && ($dblist->HTMLcode || !empty($dblist->searchString))) {
555 $this->content = $dblist->getSearchBox();
556 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
557
558 $searchButton = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->makeLinkButton();
559 $searchButton
560 ->setHref('#')
561 ->setClasses('t3js-toggle-search-toolbox')
562 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
563 ->setIcon($this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL));
564 $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->addButton(
565 $searchButton,
566 ButtonBar::BUTTON_POSITION_LEFT,
567 90
568 );
569 }
570
571 if ($this->pageinfo) {
572 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
573 }
574
575 // Build the <body> for the module
576 $this->content .= $this->body;
577 }
578
579 /**
580 * Injects the request object for the current request or subrequest
581 * Simply calls main() and init() and outputs the content
582 *
583 * @param ServerRequestInterface $request the current request
584 * @return ResponseInterface the response with the content
585 */
586 public function mainAction(ServerRequestInterface $request): ResponseInterface
587 {
588 $this->site = $request->getAttribute('site');
589 $this->siteLanguages = $this->site->getAvailableLanguages($this->getBackendUserAuthentication(), false, (int)$this->id);
590 BackendUtility::lockRecords();
591 $this->init();
592 $this->clearCache();
593 $this->main($request);
594 $this->moduleTemplate->setContent($this->content);
595 return new HtmlResponse($this->moduleTemplate->renderContent());
596 }
597
598 /**
599 * Make selector box for creating new translation in a language
600 * Displays only languages which are not yet present for the current page and
601 * that are not disabled with page TS.
602 *
603 * @param int $id Page id for which to create a new translation record of pages
604 * @return string <select> HTML element (if there were items for the box anyways...)
605 */
606 protected function languageSelector(int $id): string
607 {
608 if (!$this->getBackendUserAuthentication()->check('tables_modify', 'pages')) {
609 return '';
610 }
611 $availableTranslations = [];
612 foreach ($this->siteLanguages as $siteLanguage) {
613 if ($siteLanguage->getLanguageId() === 0) {
614 continue;
615 }
616 $availableTranslations[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle();
617 }
618 // Then, subtract the languages which are already on the page:
619 $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
620 $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'];
621 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
622 $queryBuilder->getRestrictions()->removeAll()
623 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
624 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
625 $statement = $queryBuilder->select('uid', $languageField)
626 ->from('pages')
627 ->where(
628 $queryBuilder->expr()->eq(
629 $localizationParentField,
630 $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
631 )
632 )
633 ->execute();
634 while ($pageTranslation = $statement->fetch()) {
635 unset($availableTranslations[(int)$pageTranslation[$languageField]]);
636 }
637 // If any languages are left, make selector:
638 if (!empty($availableTranslations)) {
639 $output = '<option value="">' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:new_language')) . '</option>';
640 foreach ($availableTranslations as $languageUid => $languageTitle) {
641 // Build localize command URL to DataHandler (tce_db)
642 // which redirects to FormEngine (record_edit)
643 // which, when finished editing should return back to the current page (returnUrl)
644 $parameters = [
645 'justLocalized' => 'pages:' . $id . ':' . $languageUid,
646 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
647 ];
648 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
649 $redirectUrl = (string)$uriBuilder->buildUriFromRoute('record_edit', $parameters);
650 $targetUrl = BackendUtility::getLinkToDataHandlerAction(
651 '&cmd[pages][' . $id . '][localize]=' . $languageUid,
652 $redirectUrl
653 );
654
655 $output .= '<option value="' . htmlspecialchars($targetUrl) . '">' . htmlspecialchars($languageTitle) . '</option>';
656 }
657
658 return '<div class="form-inline form-inline-spaced">'
659 . '<div class="form-group">'
660 . '<select class="form-control input-sm" name="createNewLanguage" onchange="window.location.href=this.options[this.selectedIndex].value">'
661 . $output
662 . '</select></div></div>';
663 }
664 return '';
665 }
666
667 /**
668 * @return ModuleTemplate
669 */
670 protected function getModuleTemplate(): ModuleTemplate
671 {
672 return $this->moduleTemplate;
673 }
674
675 /**
676 * @return BackendUserAuthentication
677 */
678 protected function getBackendUserAuthentication(): BackendUserAuthentication
679 {
680 return $GLOBALS['BE_USER'];
681 }
682
683 /**
684 * @return LanguageService
685 */
686 protected function getLanguageService(): LanguageService
687 {
688 return $GLOBALS['LANG'];
689 }
690
691 /**
692 * @return PageRenderer
693 */
694 protected function getPageRenderer(): PageRenderer
695 {
696 if ($this->pageRenderer === null) {
697 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
698 }
699 return $this->pageRenderer;
700 }
701 }