‪TYPO3CMS  11.5
RecordListController.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\EventDispatcher\EventDispatcherInterface;
19 use Psr\Http\Message\ResponseFactoryInterface;
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
29 use TYPO3\CMS\Backend\Utility\BackendUtility;
43 use TYPO3\CMS\Core\Page\PageRenderer;
52 
58 {
64  protected ‪$moduleTemplate;
65 
69  protected ‪$siteLanguages = [];
70 
75 
76  protected int ‪$id = 0;
77  protected array ‪$pageInfo = [];
78  protected string ‪$returnUrl = '';
79  protected array ‪$modTSconfig = [];
80 
82  protected PageRenderer ‪$pageRenderer;
83  protected EventDispatcherInterface ‪$eventDispatcher;
84  protected ‪UriBuilder ‪$uriBuilder;
86  protected ResponseFactoryInterface ‪$responseFactory;
87 
88  public function ‪__construct(
90  PageRenderer ‪$pageRenderer,
91  EventDispatcherInterface ‪$eventDispatcher,
94  ResponseFactoryInterface ‪$responseFactory
95  ) {
96  $this->iconFactory = ‪$iconFactory;
97  $this->pageRenderer = ‪$pageRenderer;
98  $this->eventDispatcher = ‪$eventDispatcher;
99  $this->uriBuilder = ‪$uriBuilder;
100  $this->moduleTemplateFactory = ‪$moduleTemplateFactory;
101  $this->responseFactory = ‪$responseFactory;
102  }
103 
110  public function ‪mainAction(ServerRequestInterface $request): ResponseInterface
111  {
112  $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
113  $this->‪getLanguageService()->‪includeLLFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
114  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/Recordlist');
115  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/RecordDownloadButton');
116  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/ClearCache');
117  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/RecordSearch');
118  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
119  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ColumnSelectorButton');
120  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/MultiRecordSelection');
121  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardPanel');
122  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/NewContentElementWizardButton');
123  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
124 
125  BackendUtility::lockRecords();
126  $parsedBody = $request->getParsedBody();
127  $queryParams = $request->getQueryParams();
128  $backendUser = $this->‪getBackendUserAuthentication();
129  $perms_clause = $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW);
130  // GPvars:
131  $this->id = (int)($parsedBody['id'] ?? $queryParams['id'] ?? 0);
132  $pointer = max(0, (int)($parsedBody['pointer'] ?? $queryParams['pointer'] ?? 0));
133  $table = (string)($parsedBody['table'] ?? $queryParams['table'] ?? '');
134  $search_field = (string)($parsedBody['search_field'] ?? $queryParams['search_field'] ?? '');
135  $search_levels = (int)($parsedBody['search_levels'] ?? $queryParams['search_levels'] ?? 0);
136  $this->returnUrl = GeneralUtility::sanitizeLocalUrl((string)($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? ''));
137  $cmd = (string)($parsedBody['cmd'] ?? $queryParams['cmd'] ?? '');
138  // Set site languages
139  $site = $request->getAttribute('site');
140  $this->siteLanguages = $site->getAvailableLanguages($this->‪getBackendUserAuthentication(), false, ‪$this->id);
141  // Loading module configuration:
142  $this->modTSconfig = BackendUtility::getPagesTSconfig($this->id)['mod.']['web_list.'] ?? [];
143  // Clean up settings:
144  $MOD_SETTINGS = BackendUtility::getModuleData(['clipBoard' => ''], (array)($parsedBody['SET'] ?? $queryParams['SET'] ?? []), 'web_list');
145  // main
146  $lang = $this->‪getLanguageService();
147  // Loading current page record and checking access:
148  $pageinfo = BackendUtility::readPageAccess($this->id, $perms_clause);
149  $access = is_array($pageinfo);
150  $this->pageInfo = is_array($pageinfo) ? $pageinfo : [];
151 
152  $this->pagePermissions = new ‪Permission($backendUser->calcPerms($pageinfo));
153  $userCanEditPage = $this->pagePermissions->editPagePermissionIsGranted() && !empty($this->id) && ($backendUser->isAdmin() || (int)$pageinfo['editlock'] === 0);
154  $pageActionsInstruction = ‪JavaScriptModuleInstruction::forRequireJS('TYPO3/CMS/Backend/PageActions');
155  if ($userCanEditPage) {
156  $pageActionsInstruction->invoke('setPageId', $this->id);
157  }
158  $this->pageRenderer->getJavaScriptRenderer()->addJavaScriptModuleInstruction($pageActionsInstruction);
159  // Apply predefined values for hidden checkboxes
160  // Set predefined value for Clipboard:
161  if (isset($this->modTSconfig['enableClipBoard'])) {
162  if ($this->modTSconfig['enableClipBoard'] === 'activated') {
163  $MOD_SETTINGS['clipBoard'] = true;
164  } elseif ($this->modTSconfig['enableClipBoard'] === 'deactivated') {
165  $MOD_SETTINGS['clipBoard'] = false;
166  }
167  }
168  if (!isset($MOD_SETTINGS['clipBoard'])) {
169  $MOD_SETTINGS['clipBoard'] = true;
170  }
171  $clipboard = $this->‪initializeClipboard($request, (bool)$MOD_SETTINGS['clipBoard']);
172  $enableListing = $access || ($this->id === 0 && $search_levels !== 0 && $search_field !== '');
173 
174  // Initialize the dblist object:
175  $dblist = GeneralUtility::makeInstance(DatabaseRecordList::class);
176  $dblist->setModuleData($MOD_SETTINGS ?? []);
177  $dblist->calcPerms = ‪$this->pagePermissions;
178  $dblist->returnUrl = ‪$this->returnUrl;
179  $dblist->showClipboardActions = true;
180  $dblist->disableSingleTableView = $this->modTSconfig['disableSingleTableView'] ?? false;
181  $dblist->listOnlyInSingleTableMode = $this->modTSconfig['listOnlyInSingleTableView'] ?? false;
182  $dblist->hideTables = $this->modTSconfig['hideTables'] ?? '';
183  $dblist->hideTranslations = $this->modTSconfig['hideTranslations'] ?? false;
184  $dblist->tableTSconfigOverTCA = $this->modTSconfig['table.'] ?? false;
185  $dblist->allowedNewTables = ‪GeneralUtility::trimExplode(',', $this->modTSconfig['allowedNewTables'] ?? '', true);
186  $dblist->deniedNewTables = ‪GeneralUtility::trimExplode(',', $this->modTSconfig['deniedNewTables'] ?? '', true);
187  $dblist->pageRow = ‪$this->pageInfo;
188  $dblist->modTSconfig = ‪$this->modTSconfig;
189  $dblist->setLanguagesAllowedForUser($this->siteLanguages);
190  $clickTitleMode = trim($this->modTSconfig['clickTitleMode'] ?? '');
191  $dblist->clickTitleMode = $clickTitleMode === '' ? 'edit' : $clickTitleMode;
192  if (isset($this->modTSconfig['tableDisplayOrder.'])) {
193  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
194  $dblist->setTableDisplayOrder($typoScriptService->convertTypoScriptArrayToPlainArray($this->modTSconfig['tableDisplayOrder.']));
195  }
196 
197  $dblist->clipObj = $clipboard;
198  // 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:
199  $tableOutput = '';
200  if ($enableListing) {
201  // Deleting records...:
202  // 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.
203  if ($cmd === 'delete' && $request->getMethod() === 'POST') {
204  $items = $clipboard->cleanUpCBC((array)($parsedBody['CBC'] ?? []), (string)($parsedBody['cmd_table'] ?? ''), true);
205  if (!empty($items)) {
206  // Create data handler command array
207  $dataHandlerCmd = [];
208  foreach ($items as $iK => $value) {
209  $iKParts = explode('|', (string)$iK);
210  $dataHandlerCmd[$iKParts[0]][$iKParts[1]]['delete'] = 1;
211  }
212  $tce = GeneralUtility::makeInstance(DataHandler::class);
213  $tce->start([], $dataHandlerCmd);
214  $tce->process_cmdmap();
215  if (isset($dataHandlerCmd['pages'])) {
216  BackendUtility::setUpdateSignal('updatePageTree');
217  }
218  $tce->printLogErrorMessages();
219  }
220  }
221  // Initialize the listing object, dblist, for rendering the list:
222  $dblist->start($this->id, $table, $pointer, $search_field, $search_levels);
223  $dblist->setDispFields();
224  // Render the list of tables:
225  $tableOutput = $dblist->generateList();
226 
227  // Add JavaScript functions to the page:
228  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Element/ImmediateActionElement');
229 
230  // Setting up the context sensitive menu:
231  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
232  }
233  // access
234  // Begin to compile the whole page, starting out with page header:
235  if (!$this->id) {
236  $title = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
237  } else {
238  $title = $pageinfo['title'] ?? '';
239  }
240  $body = ‪ImmediateActionElement::moduleStateUpdate('web', (int)$this->id);
241  $body .= $this->moduleTemplate->header($title, $this->‪isPageEditable());
242 
243  // Additional header content
245  $additionalRecordListEvent = $this->eventDispatcher->dispatch(new RenderAdditionalContentToRecordListEvent($request));
246  $body .= $additionalRecordListEvent->getAdditionalContentAbove();
247  $this->moduleTemplate->setTitle(
248  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:mlang_tabs_tab'),
249  $title
250  );
251 
252  $beforeOutput = '';
253  ‪$output = '';
254  // Show the selector to add page translations, but only when in "default" mode.
255  // If not disabled via module TSconfig and the user is allowed, also show the page translations table.
256  if ($this->id && !$search_field && !$cmd && !$table) {
257  $beforeOutput .= $this->‪languageSelector($request->getAttribute('normalizedParams')->getRequestUri());
258  if ($this->‪showPageTranslations()) {
259  $pageTranslationsDatabaseRecordList = clone $dblist;
260  $pageTranslationsDatabaseRecordList->listOnlyInSingleTableMode = false;
261  $pageTranslationsDatabaseRecordList->disableSingleTableView = true;
262  $pageTranslationsDatabaseRecordList->deniedNewTables = ['pages'];
263  $pageTranslationsDatabaseRecordList->hideTranslations = '';
264  $pageTranslationsDatabaseRecordList->setLanguagesAllowedForUser($this->siteLanguages);
265  $pageTranslationsDatabaseRecordList->showOnlyTranslatedRecords(true);
266  ‪$output .= $pageTranslationsDatabaseRecordList->getTable('pages', $this->id);
267  }
268  }
269 
270  // search box toolbar
271  if (!($this->modTSconfig['disableSearchBox'] ?? false) && ($tableOutput || !empty($search_field))) {
272  $beforeOutput .= $this->‪renderSearchBox($dblist, $search_field, $search_levels);
273  }
274 
275  if (!empty($tableOutput)) {
276  ‪$output .= $tableOutput;
277  } else {
278  if (isset(‪$GLOBALS['TCA'][$table]['ctrl']['title'])) {
279  if (strpos(‪$GLOBALS['TCA'][$table]['ctrl']['title'], 'LLL:') === 0) {
280  $ll = sprintf($lang->getLL('noRecordsOfTypeOnThisPage'), $lang->sL(‪$GLOBALS['TCA'][$table]['ctrl']['title']));
281  } else {
282  $ll = sprintf($lang->getLL('noRecordsOfTypeOnThisPage'), ‪$GLOBALS['TCA'][$table]['ctrl']['title']);
283  }
284  } else {
285  $ll = $lang->getLL('noRecordsOnThisPage');
286  }
287  $flashMessage = GeneralUtility::makeInstance(
288  FlashMessage::class,
289  $ll,
290  '',
292  );
293  unset($ll);
294  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
295  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
296  $defaultFlashMessageQueue->enqueue($flashMessage);
297  }
298 
299  if ($beforeOutput) {
300  $body .= '<div class="row">' . $beforeOutput . '</div>';
301  }
302  $body .= ‪$output;
303  // If a listing was produced, create the page footer
304  if ($tableOutput) {
305  // Adding checkbox option for clipboard display
306  $body .= '
307  <div class="mb-3">
308  <form action="" method="post">';
309 
310  // Add "clipboard" checkbox:
311  if (($this->modTSconfig['enableClipBoard'] ?? '') === 'selectable') {
312  $body .= '<div class="form-check form-switch">' .
313  BackendUtility::getFuncCheck($this->id, 'SET[clipBoard]', ($MOD_SETTINGS['clipBoard'] ?? ''), '', $table ? '&table=' . $table : '', 'id="checkShowClipBoard"') .
314  '<label class="form-check-label" for="checkShowClipBoard">' .
315  BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', htmlspecialchars($lang->getLL('showClipBoard'))) .
316  '</label>' .
317  '</div>';
318  }
319 
320  $body .= '
321  </form>
322  </div>';
323  }
324  // Printing clipboard if enabled
325  if ($MOD_SETTINGS['clipBoard'] && ($tableOutput || $clipboard->hasElements())) {
326  $body .= '<typo3-backend-clipboard-panel return-url="' . htmlspecialchars($dblist->listURL()) . '"></typo3-backend-clipboard-panel>';
327  }
328  // Additional footer content
329  $body .= $additionalRecordListEvent->getAdditionalContentBelow();
330  // Setting up the buttons for docheader
331  $this->‪getDocHeaderButtons(
332  $clipboard,
333  $queryParams,
334  $table,
335  $dblist->listURL(),
336  $MOD_SETTINGS
337  );
338 
339  if ($pageinfo) {
340  $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageinfo);
341  }
342 
343  $this->moduleTemplate->setContent($body);
344  return $this->‪htmlResponse($this->moduleTemplate->renderContent());
345  }
346 
354  protected function ‪initializeClipboard(ServerRequestInterface $request, bool $isClipboardShown): Clipboard
355  {
356  $clipboard = GeneralUtility::makeInstance(Clipboard::class);
357  $cmd = (string)($request->getParsedBody()['cmd'] ?? $request->getQueryParams()['cmd'] ?? '');
358  // Initialize - reads the clipboard content from the user session
359  $clipboard->initializeClipboard($request);
360  // Clipboard actions are handled:
361  // CB is the clipboard command array
362  $CB = array_replace_recursive($request->getQueryParams()['CB'] ?? [], $request->getParsedBody()['CB'] ?? []);
363  if ($cmd === 'copyMarked' || $cmd === 'removeMarked') {
364  // Get CBC from request, and map the element values (true => copy, false => remove)
365  $CBC = array_map(static fn() => ($cmd === 'copyMarked'), (array)($request->getParsedBody()['CBC'] ?? []));
366  $cmd_table = (string)($request->getParsedBody()['cmd_table'] ?? $request->getQueryParams()['cmd_table'] ?? '');
367  // Cleanup CBC
368  $CB['el'] = $clipboard->cleanUpCBC($CBC, $cmd_table);
369  }
370  if (!$isClipboardShown) {
371  // If the clipboard is NOT shown, set the pad to 'normal'.
372  $CB['setP'] = 'normal';
373  }
374  // Execute commands.
375  $clipboard->setCmd($CB);
376  // Clean up pad
377  $clipboard->cleanCurrent();
378  // Save the clipboard content
379  $clipboard->endClipboard();
380  return $clipboard;
381  }
382 
383  protected function ‪renderSearchBox(‪DatabaseRecordList $dblist, string $searchWord, int $searchLevels): string
384  {
385  $searchBoxVisible = !empty($dblist->searchString);
386  $searchBox = GeneralUtility::makeInstance(RecordSearchBoxComponent::class)
387  ->setAllowedSearchLevels((array)($this->modTSconfig['searchLevel.']['items.'] ?? []))
388  ->setSearchWord($searchWord)
389  ->setSearchLevel($searchLevels)
390  ->render($dblist->‪listURL('', '-1', 'pointer,search_field'));
391 
392  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
393  $searchButton = $buttonBar->makeLinkButton();
394  $searchButton
395  ->setHref('#')
396  ->setClasses('t3js-toggle-search-toolbox')
397  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
398  ->setIcon($this->iconFactory->getIcon('actions-search', ‪Icon::SIZE_SMALL));
399  $buttonBar->addButton(
400  $searchButton,
402  90
403  );
404  return '<div class="col-6" style="' . ($searchBoxVisible ?: 'display: none') . '" id="db_list-searchbox-toolbar">' . $searchBox . '</div>';
405  }
406 
417  protected function ‪getDocHeaderButtons(Clipboard $clipboard, array $queryParams, string $table, string $listUrl, array $moduleSettings): void
418  {
419  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
420  $backendUser = $this->‪getBackendUserAuthentication();
421  $lang = $this->‪getLanguageService();
422  // CSH
423  if (!$this->id) {
424  $fieldName = 'list_module_root';
425  } else {
426  $fieldName = 'list_module';
427  }
428  $cshButton = $buttonBar->makeHelpButton()
429  ->setModuleName('xMOD_csh_corebe')
430  ->setFieldName($fieldName);
431  $buttonBar->addButton($cshButton);
432  // New record on pages that are not locked by editlock
433  if (!($this->modTSconfig['noCreateRecordsLink'] ?? false) && $this->‪editLockPermissions()) {
434  $newRecordButton = $buttonBar->makeLinkButton()
435  ->setHref((string)$this->uriBuilder->buildUriFromRoute('db_new', ['id' => $this->id, 'returnUrl' => $listUrl]))
436  ->setTitle($lang->getLL('newRecordGeneral'))
437  ->setIcon($this->iconFactory->getIcon('actions-add', ‪Icon::SIZE_SMALL));
438  $buttonBar->addButton($newRecordButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 10);
439  }
440 
441  if ($this->id !== 0) {
442  if ($this->‪canCreatePreviewLink()) {
443  $previewDataAttributes = ‪PreviewUriBuilder::create((int)$this->id)
444  ->withRootLine(BackendUtility::BEgetRootLine($this->id))
445  ->buildDispatcherDataAttributes();
446  $viewButton = $buttonBar->makeLinkButton()
447  ->setHref('#')
448  ->setDataAttributes($previewDataAttributes ?? [])
449  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
450  ->setIcon($this->iconFactory->getIcon('actions-view-page', ‪Icon::SIZE_SMALL));
451  $buttonBar->addButton($viewButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 20);
452  }
453  // If edit permissions are set, see
454  // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
455  if ($this->‪isPageEditable()) {
456  // Edit
457  $editLink = $this->uriBuilder->buildUriFromRoute('record_edit', [
458  'edit' => [
459  'pages' => [
460  $this->id => 'edit',
461  ],
462  ],
463  'returnUrl' => $listUrl,
464  ]);
465  $editButton = $buttonBar->makeLinkButton()
466  ->setHref($editLink)
467  ->setTitle($lang->getLL('editPage'))
468  ->setIcon($this->iconFactory->getIcon('actions-page-open', ‪Icon::SIZE_SMALL));
469  $buttonBar->addButton($editButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 20);
470  }
471  }
472 
473  // Paste
474  if (($this->pagePermissions->createPagePermissionIsGranted() || $this->pagePermissions->editContentPermissionIsGranted()) && $this->editLockPermissions()) {
475  $elFromTable = $clipboard->elFromTable();
476  if (!empty($elFromTable)) {
477  $confirmMessage = $clipboard->confirmMsgText('pages', $this->pageInfo, 'into', $elFromTable);
478  $pasteButton = $buttonBar->makeLinkButton()
479  ->setHref($clipboard->pasteUrl('', $this->id))
480  ->setTitle($lang->getLL('clip_paste'))
481  ->setClasses('t3js-modal-trigger')
482  ->setDataAttributes([
483  'severity' => 'warning',
484  'bs-content' => $confirmMessage,
485  'title' => $lang->getLL('clip_paste'),
486  ])
487  ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', ‪Icon::SIZE_SMALL));
488  $buttonBar->addButton($pasteButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 40);
489  }
490  }
491  // Cache
492  if ($this->id !== 0) {
493  $clearCacheButton = $buttonBar->makeLinkButton()
494  ->setHref('#')
495  ->setDataAttributes(['id' => $this->id])
496  ->setClasses('t3js-clear-page-cache')
497  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
498  ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', ‪Icon::SIZE_SMALL));
499  $buttonBar->addButton($clearCacheButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
500  }
501  if ($table && (!isset($this->modTSconfig['noExportRecordsLinks'])
502  || (isset($this->modTSconfig['noExportRecordsLinks'])
503  && !$this->modTSconfig['noExportRecordsLinks']))
504  ) {
505  // Export
507  $url = (string)$this->uriBuilder->buildUriFromRoute('tx_impexp_export', ['tx_impexp' => ['list' => [$table . ':' . $this->id]]]);
508  $exportButton = $buttonBar->makeLinkButton()
509  ->setHref($url)
510  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.export'))
511  ->setIcon($this->iconFactory->getIcon('actions-document-export-t3d', ‪Icon::SIZE_SMALL))
512  ->setShowLabelText(true);
513  $buttonBar->addButton($exportButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 40);
514  }
515  }
516  // Reload
517  $reloadButton = $buttonBar->makeLinkButton()
518  ->setHref($listUrl)
519  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
520  ->setIcon($this->iconFactory->getIcon('actions-refresh', ‪Icon::SIZE_SMALL));
521  $buttonBar->addButton($reloadButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
522 
523  // Shortcut
524  $shortCutButton = $buttonBar->makeShortcutButton()->setRouteIdentifier('web_list');
525  $arguments = [
526  'id' => ‪$this->id,
527  ];
528  $potentialArguments = [
529  'pointer',
530  'table',
531  'search_field',
532  'search_levels',
533  'sortField',
534  'sortRev',
535  ];
536  foreach ($potentialArguments as $argument) {
537  if (!empty($queryParams[$argument])) {
538  $arguments[$argument] = $queryParams[$argument];
539  }
540  }
541  foreach ($moduleSettings as $moduleSettingKey => $moduleSettingValue) {
542  $arguments['GET'][$moduleSettingKey] = $moduleSettingValue;
543  }
544  $shortCutButton->setArguments($arguments);
545  $shortCutButton->setDisplayName($this->‪getShortcutTitle($arguments));
546  $buttonBar->addButton($shortCutButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
547 
548  // Back
549  if ($this->returnUrl) {
550  $backButton = $buttonBar->makeLinkButton()
551  ->setHref($this->returnUrl)
552  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
553  ->setIcon($this->iconFactory->getIcon('actions-view-go-back', ‪Icon::SIZE_SMALL));
554  $buttonBar->addButton($backButton, ‪ButtonBar::BUTTON_POSITION_LEFT);
555  }
556  }
557 
567  protected function ‪languageSelector(string $requestUri): string
568  {
569  if (!$this->‪getBackendUserAuthentication()->check('tables_modify', 'pages')) {
570  return '';
571  }
572  $availableTranslations = [];
573  foreach ($this->siteLanguages as $siteLanguage) {
574  if ($siteLanguage->getLanguageId() === 0) {
575  continue;
576  }
577  $availableTranslations[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle();
578  }
579  // Then, subtract the languages which are already on the page:
580  $localizationParentField = ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
581  $languageField = ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'];
582  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
583  $queryBuilder->getRestrictions()->removeAll()
584  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
585  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUserAuthentication()->workspace));
586  $statement = $queryBuilder->select('uid', $languageField)
587  ->from('pages')
588  ->where(
589  $queryBuilder->expr()->eq(
590  $localizationParentField,
591  $queryBuilder->createNamedParameter($this->id, ‪Connection::PARAM_INT)
592  )
593  )
594  ->executeQuery();
595  while ($pageTranslation = $statement->fetchAssociative()) {
596  unset($availableTranslations[(int)$pageTranslation[$languageField]]);
597  }
598  // If any languages are left, make selector:
599  if (!empty($availableTranslations)) {
600  ‪$output = '<option value="">' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:new_language')) . '</option>';
601  foreach ($availableTranslations as $languageUid => $languageTitle) {
602  // Build localize command URL to DataHandler (tce_db)
603  // which redirects to FormEngine (record_edit)
604  // which, when finished editing should return back to the current page (returnUrl)
605  $parameters = [
606  'justLocalized' => 'pages:' . $this->id . ':' . $languageUid,
607  'returnUrl' => $requestUri,
608  ];
609  $redirectUrl = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $parameters);
610  $params = [];
611  $params['redirect'] = $redirectUrl;
612  $params['cmd']['pages'][‪$this->id]['localize'] = $languageUid;
613  $targetUrl = (string)$this->uriBuilder->buildUriFromRoute('tce_db', $params);
614  ‪$output .= '<option value="' . htmlspecialchars($targetUrl) . '">' . htmlspecialchars($languageTitle) . '</option>';
615  }
616 
617  return '<div class="col-auto">'
618  . '<select class="form-select" name="createNewLanguage" data-global-event="change" data-action-navigate="$value">'
619  . ‪$output
620  . '</select></div>';
621  }
622  return '';
623  }
624 
629  protected function ‪canCreatePreviewLink(): bool
630  {
631  if (isset($this->modTSconfig['noViewWithDokTypes'])) {
632  $noViewDokTypes = ‪GeneralUtility::trimExplode(',', $this->modTSconfig['noViewWithDokTypes'], true);
633  } else {
634  $noViewDokTypes = [
637  ];
638  }
639 
640  return !in_array($this->pageInfo['doktype'] ?? 0, $noViewDokTypes);
641  }
642 
649  protected function ‪editLockPermissions(): bool
650  {
651  return $this->‪getBackendUserAuthentication()->‪isAdmin() || !($this->pageInfo['editlock'] ?? false);
652  }
653 
660  protected function ‪getShortcutTitle(array $arguments): string
661  {
662  $pageTitle = '';
663  $tableTitle = '';
664  $languageService = $this->‪getLanguageService();
665 
666  if (isset($arguments['table'])) {
667  $tableTitle = ': ' . (isset(‪$GLOBALS['TCA'][$arguments['table']]['ctrl']['title']) ? $languageService->sL(‪$GLOBALS['TCA'][$arguments['table']]['ctrl']['title']) : $arguments['table']);
668  }
669 
670  if ($this->pageInfo !== []) {
671  $pageTitle = BackendUtility::getRecordTitle('pages', $this->pageInfo);
672  }
673 
674  return trim(sprintf(
675  $languageService->sL('LLL:EXT:recordlist/Resources/Private/Language/locallang.xlf:shortcut.title'),
676  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:mlang_tabs_tab'),
677  $tableTitle,
678  $pageTitle,
679  $this->id
680  ));
681  }
682 
683  protected function ‪showPageTranslations(): bool
684  {
685  if (!$this->‪getBackendUserAuthentication()->check('tables_select', 'pages')) {
686  return false;
687  }
688 
689  if (isset($this->modTSconfig['table.']['pages.']['hideTable'])) {
690  return !$this->modTSconfig['table.']['pages.']['hideTable'];
691  }
692 
693  $hideTables = $this->modTSconfig['hideTables'] ?? '';
694  return !(‪$GLOBALS['TCA']['pages']['ctrl']['hideTable'] ?? false)
695  && $hideTables !== '*'
696  && !in_array('pages', ‪GeneralUtility::trimExplode(',', $hideTables), true);
697  }
698 
699  protected function ‪htmlResponse(string $html): ResponseInterface
700  {
701  $response = $this->responseFactory->createResponse()
702  ->withHeader('Content-Type', 'text/html; charset=utf-8');
703  $response->getBody()->write($html);
704  return $response;
705  }
706 
710  protected function ‪getBackendUserAuthentication(): BackendUserAuthentication
711  {
712  return ‪$GLOBALS['BE_USER'];
713  }
714 
718  protected function ‪getLanguageService(): LanguageService
719  {
720  return ‪$GLOBALS['LANG'];
721  }
722 
728  protected function ‪isPageEditable(): bool
729  {
730  if (‪$GLOBALS['TCA']['pages']['ctrl']['readOnly'] ?? false) {
731  return false;
732  }
733  $backendUser = $this->‪getBackendUserAuthentication();
734  if ($backendUser->isAdmin()) {
735  return true;
736  }
737  if (‪$GLOBALS['TCA']['pages']['ctrl']['adminOnly'] ?? false) {
738  return false;
739  }
740 
741  return $this->pageInfo !== []
742  && $this->‪editLockPermissions()
743  && $this->pagePermissions->editPagePermissionIsGranted()
744  && $backendUser->checkLanguageAccess(0)
745  && $backendUser->check('tables_modify', 'pages');
746  }
747 }
‪TYPO3\CMS\Core\DataHandling\DataHandler
Definition: DataHandler.php:86
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Recordlist\Controller\RecordListController\htmlResponse
‪htmlResponse(string $html)
Definition: RecordListController.php:696
‪TYPO3\CMS\Recordlist\Controller\RecordListController\showPageTranslations
‪showPageTranslations()
Definition: RecordListController.php:680
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_LEFT
‪const BUTTON_POSITION_LEFT
Definition: ButtonBar.php:36
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:32
‪TYPO3\CMS\Backend\Clipboard\Clipboard
Definition: Clipboard.php:49
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: RecordListController.php:80
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder\create
‪static static create(int $pageId, string $alternativeUri=null)
Definition: PreviewUriBuilder.php:75
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:29
‪TYPO3\CMS\Recordlist\Controller\RecordListController\initializeClipboard
‪Clipboard initializeClipboard(ServerRequestInterface $request, bool $isClipboardShown)
Definition: RecordListController.php:351
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\listURL
‪string listURL($altId='', $table='-1', $exclList='')
Definition: DatabaseRecordList.php:2847
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$siteLanguages
‪SiteLanguage[] $siteLanguages
Definition: RecordListController.php:67
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isAdmin
‪bool isAdmin()
Definition: BackendUserAuthentication.php:245
‪TYPO3\CMS\Recordlist\Controller\RecordListController\getLanguageService
‪LanguageService getLanguageService()
Definition: RecordListController.php:715
‪TYPO3\CMS\Recordlist\Controller\RecordListController\isPageEditable
‪bool isPageEditable()
Definition: RecordListController.php:725
‪TYPO3\CMS\Recordlist\Controller\RecordListController\__construct
‪__construct(IconFactory $iconFactory, PageRenderer $pageRenderer, EventDispatcherInterface $eventDispatcher, UriBuilder $uriBuilder, ModuleTemplateFactory $moduleTemplateFactory, ResponseFactoryInterface $responseFactory)
Definition: RecordListController.php:85
‪TYPO3\CMS\Recordlist\Event\RenderAdditionalContentToRecordListEvent
Definition: RenderAdditionalContentToRecordListEvent.php:28
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$iconFactory
‪IconFactory $iconFactory
Definition: RecordListController.php:78
‪TYPO3\CMS\Backend\Domain\Model\Element\ImmediateActionElement\moduleStateUpdate
‪static moduleStateUpdate(string $module, $identifier, bool $select=null)
Definition: ImmediateActionElement.php:39
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$moduleTemplateFactory
‪ModuleTemplateFactory $moduleTemplateFactory
Definition: RecordListController.php:82
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\forRequireJS
‪static self forRequireJS(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:49
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:46
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
Definition: DatabaseRecordList.php:59
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$uriBuilder
‪UriBuilder $uriBuilder
Definition: RecordListController.php:81
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$pagePermissions
‪Permission $pagePermissions
Definition: RecordListController.php:71
‪TYPO3\CMS\Backend\Clipboard\Clipboard\pasteUrl
‪string pasteUrl(string $table, $identifier, bool $setRedirect=true, array $update=null)
Definition: Clipboard.php:557
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$returnUrl
‪string $returnUrl
Definition: RecordListController.php:75
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$moduleTemplate
‪ModuleTemplate $moduleTemplate
Definition: RecordListController.php:63
‪TYPO3\CMS\Recordlist\Controller\RecordListController\renderSearchBox
‪renderSearchBox(DatabaseRecordList $dblist, string $searchWord, int $searchLevels)
Definition: RecordListController.php:380
‪TYPO3\CMS\Recordlist\Controller\RecordListController
Definition: RecordListController.php:58
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$responseFactory
‪ResponseFactoryInterface $responseFactory
Definition: RecordListController.php:83
‪TYPO3\CMS\Recordlist\Controller\RecordListController\mainAction
‪ResponseInterface mainAction(ServerRequestInterface $request)
Definition: RecordListController.php:107
‪TYPO3\CMS\Recordlist\Controller
Definition: AbstractLinkBrowserController.php:16
‪TYPO3\CMS\Recordlist\View\RecordSearchBoxComponent
Definition: RecordSearchBoxComponent.php:30
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$pageInfo
‪array $pageInfo
Definition: RecordListController.php:74
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:35
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$pageRenderer
‪PageRenderer $pageRenderer
Definition: RecordListController.php:79
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:116
‪TYPO3\CMS\Recordlist\Controller\RecordListController\editLockPermissions
‪bool editLockPermissions()
Definition: RecordListController.php:646
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$id
‪int $id
Definition: RecordListController.php:73
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:25
‪$output
‪$output
Definition: annotationChecker.php:121
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$modTSconfig
‪array $modTSconfig
Definition: RecordListController.php:76
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Messaging\AbstractMessage\INFO
‪const INFO
Definition: AbstractMessage.php:28
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder
Definition: PreviewUriBuilder.php:32
‪TYPO3\CMS\Recordlist\Controller\RecordListController\languageSelector
‪string languageSelector(string $requestUri)
Definition: RecordListController.php:564
‪TYPO3\CMS\Recordlist\Controller\RecordListController\getShortcutTitle
‪string getShortcutTitle(array $arguments)
Definition: RecordListController.php:657
‪TYPO3\CMS\Core\Localization\LanguageService\includeLLFile
‪array includeLLFile($fileRef)
Definition: LanguageService.php:271
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:41
‪TYPO3\CMS\Backend\Domain\Model\Element\ImmediateActionElement
Definition: ImmediateActionElement.php:28
‪TYPO3\CMS\Backend\Clipboard\Clipboard\confirmMsgText
‪string confirmMsgText(string $table, $reference, string $type, array $selectedElements, string $columnLabel='')
Definition: Clipboard.php:584
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static bool isLoaded($key)
Definition: ExtensionManagementUtility.php:114
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:117
‪TYPO3\CMS\Backend\Clipboard\Clipboard\elFromTable
‪array elFromTable(string $matchTable='', string $padIdentifier='')
Definition: Clipboard.php:719
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Recordlist\Controller\RecordListController\canCreatePreviewLink
‪canCreatePreviewLink()
Definition: RecordListController.php:626
‪TYPO3\CMS\Recordlist\Controller\RecordListController\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: RecordListController.php:707
‪TYPO3\CMS\Recordlist\Controller\RecordListController\getDocHeaderButtons
‪getDocHeaderButtons(Clipboard $clipboard, array $queryParams, string $table, string $listUrl, array $moduleSettings)
Definition: RecordListController.php:414
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:40