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