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