TYPO3 CMS  TYPO3_8-7
ImportExportController.php
Go to the documentation of this file.
1 <?php
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 
46 
51 {
55  protected $uploadedFiles = [];
56 
62  public $pageinfo;
63 
67  protected $export;
68 
72  protected $import;
73 
77  protected $fileProcessor;
78 
82  protected $lang = null;
83 
87  protected $treeHTML = '';
88 
92  protected $iconFactory;
93 
99  protected $moduleName = 'xMOD_tximpexp';
100 
106  protected $moduleTemplate;
107 
113  protected $shortcutName;
114 
120  protected $presetRepository;
121 
125  protected $standaloneView = null;
126 
130  protected $excludeDisabledRecords = false;
131 
137  protected $returnUrl;
138 
142  public function __construct()
143  {
144  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
145  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
146  $this->presetRepository = GeneralUtility::makeInstance(PresetRepository::class);
147 
148  $templatePath = ExtensionManagementUtility::extPath('impexp') . 'Resources/Private/';
149 
150  /* @var $view StandaloneView */
151  $this->standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
152  $this->standaloneView->setTemplateRootPaths([$templatePath . 'Templates/ImportExport/']);
153  $this->standaloneView->setLayoutRootPaths([$templatePath . 'Layouts/']);
154  $this->standaloneView->setPartialRootPaths([$templatePath . 'Partials/']);
155  $this->standaloneView->getRequest()->setControllerExtensionName('impexp');
156  }
157 
161  public function init()
162  {
163  $this->MCONF['name'] = $this->moduleName;
164  parent::init();
165  $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
166  $this->lang = $this->getLanguageService();
167  }
168 
176  public function main()
177  {
178  $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf');
179 
180  // Start document template object:
181  // We keep this here, in case somebody relies on the old doc being here
182  $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
183  $this->doc->bodyTagId = 'imp-exp-mod';
184  $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
185  if (is_array($this->pageinfo)) {
186  $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
187  }
188  // Setting up the context sensitive menu:
189  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
190  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Impexp/ImportExport');
191  $this->moduleTemplate->addJavaScriptCode(
192  'ImpexpInLineJS',
193  'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
194  );
195 
196  // Input data grabbed:
197  $inData = GeneralUtility::_GP('tx_impexp');
198  if ($inData === null) {
199  // This happens if the post request was larger than allowed on the server
200  // We set the import action as default and output a user information
201  $inData = [
202  'action' => 'import',
203  ];
204  $flashMessage = GeneralUtility::makeInstance(
205  FlashMessage::class,
206  $this->getLanguageService()->getLL('importdata_upload_nodata'),
207  $this->getLanguageService()->getLL('importdata_upload_error'),
209  );
210  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
211  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
212  $defaultFlashMessageQueue->enqueue($flashMessage);
213  }
214  if (!array_key_exists('excludeDisabled', $inData)) {
215  // flag doesn't exist initially; state is on by default
216  $inData['excludeDisabled'] = 1;
217  }
218  $this->standaloneView->assign('moduleUrl', BackendUtility::getModuleUrl('xMOD_tximpexp'));
219  $this->standaloneView->assign('id', $this->id);
220  $this->standaloneView->assign('inData', $inData);
221 
222  switch ((string)$inData['action']) {
223  case 'export':
224  $this->shortcutName = $this->lang->getLL('title_export');
225  // Call export interface
226  $this->exportData($inData);
227  $this->standaloneView->setTemplate('Export.html');
228  break;
229  case 'import':
230  $backendUser = $this->getBackendUser();
231  $isEnabledForNonAdmin = $backendUser->getTSConfig('options.impexp.enableImportForNonAdminUser');
232  if (!$backendUser->isAdmin() && empty($isEnabledForNonAdmin['value'])) {
233  throw new \RuntimeException(
234  'Import module is disabled for non admin users and '
235  . 'userTsConfig options.impexp.enableImportForNonAdminUser is not enabled.',
236  1464435459
237  );
238  }
239  $this->shortcutName = $this->lang->getLL('title_import');
240  if (GeneralUtility::_POST('_upload')) {
241  $this->checkUpload();
242  }
243  // Finally: If upload went well, set the new file as the import file:
244  if (!empty($this->uploadedFiles[0])) {
245  // Only allowed extensions....
246  $extension = $this->uploadedFiles[0]->getExtension();
247  if ($extension === 't3d' || $extension === 'xml') {
248  $inData['file'] = $this->uploadedFiles[0]->getCombinedIdentifier();
249  }
250  }
251  // Call import interface:
252  $this->importData($inData);
253  $this->standaloneView->setTemplate('Import.html');
254  break;
255  }
256 
257  // Setting up the buttons and markers for docheader
258  $this->getButtons();
259  }
260 
296  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
297  {
298  $GLOBALS['SOBE'] = $this;
299  $this->init();
300  $this->main();
301  $this->moduleTemplate->setContent($this->standaloneView->render());
302  $response->getBody()->write($this->moduleTemplate->renderContent());
303 
304  return $response;
305  }
306 
312  protected function getButtons()
313  {
314  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
315  if ($this->getBackendUser()->mayMakeShortcut()) {
316  $shortcutButton = $buttonBar->makeShortcutButton()
317  ->setGetVariables(['tx_impexp'])
318  ->setDisplayName($this->shortcutName)
319  ->setModuleName($this->moduleName);
320  $buttonBar->addButton($shortcutButton);
321  }
322  // back button
323  if ($this->returnUrl) {
324  $backButton = $buttonBar->makeLinkButton()
325  ->setHref($this->returnUrl)
326  ->setTitle($this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
327  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
328  $buttonBar->addButton($backButton);
329  }
330  // Input data grabbed:
331  $inData = GeneralUtility::_GP('tx_impexp');
332  if ((string)$inData['action'] === 'import') {
333  if ($this->id && is_array($this->pageinfo) || $this->getBackendUser()->user['admin'] && !$this->id) {
334  if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
335  // View
336  $onClick = BackendUtility::viewOnClick(
337  $this->pageinfo['uid'],
338  '',
339  BackendUtility::BEgetRootLine($this->pageinfo['uid'])
340  );
341  $viewButton = $buttonBar->makeLinkButton()
342  ->setTitle($this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
343  ->setHref('#')
344  ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL))
345  ->setOnClick($onClick);
346  $buttonBar->addButton($viewButton);
347  }
348  }
349  }
350  }
351 
352  /**************************
353  * EXPORT FUNCTIONS
354  **************************/
355 
365  public function exportData($inData)
366  {
367  // BUILDING EXPORT DATA:
368  // Processing of InData array values:
369  $inData['pagetree']['maxNumber'] = MathUtility::forceIntegerInRange($inData['pagetree']['maxNumber'], 1, 1000000, 100);
370  $inData['listCfg']['maxNumber'] = MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1, 1000000, 100);
371  $inData['maxFileSize'] = MathUtility::forceIntegerInRange($inData['maxFileSize'], 1, 1000000, 1000);
372  $inData['filename'] = trim(preg_replace('/[^[:alnum:]._-]*/', '', preg_replace('/\\.(t3d|xml)$/', '', $inData['filename'])));
373  if (strlen($inData['filename'])) {
374  $inData['filename'] .= $inData['filetype'] === 'xml' ? '.xml' : '.t3d';
375  }
376  // Set exclude fields in export object:
377  if (!is_array($inData['exclude'])) {
378  $inData['exclude'] = [];
379  }
380  // Saving/Loading/Deleting presets:
381  $this->presetRepository->processPresets($inData);
382  // Create export object and configure it:
383  $this->export = GeneralUtility::makeInstance(Export::class);
384  $this->export->init(0);
385  $this->export->maxFileSize = $inData['maxFileSize'] * 1024;
386  $this->export->excludeMap = (array)$inData['exclude'];
387  $this->export->softrefCfg = (array)$inData['softrefCfg'];
388  $this->export->extensionDependencies = ($inData['extension_dep'] === '') ? [] : (array)$inData['extension_dep'];
389  $this->export->showStaticRelations = $inData['showStaticRelations'];
390  $this->export->includeExtFileResources = !$inData['excludeHTMLfileResources'];
391  $this->excludeDisabledRecords = (bool)$inData['excludeDisabled'];
392  $this->export->setExcludeDisabledRecords($this->excludeDisabledRecords);
393 
394  // Static tables:
395  if (is_array($inData['external_static']['tables'])) {
396  $this->export->relStaticTables = $inData['external_static']['tables'];
397  }
398  // Configure which tables external relations are included for:
399  if (is_array($inData['external_ref']['tables'])) {
400  $this->export->relOnlyTables = $inData['external_ref']['tables'];
401  }
402  $saveFilesOutsideExportFile = false;
403  if (isset($inData['save_export']) && isset($inData['saveFilesOutsideExportFile']) && $inData['saveFilesOutsideExportFile'] === '1') {
404  $this->export->setSaveFilesOutsideExportFile(true);
405  $saveFilesOutsideExportFile = true;
406  }
407  $this->export->setHeaderBasics();
408  // Meta data setting:
409 
410  $beUser = $this->getBackendUser();
411  $this->export->setMetaData(
412  $inData['meta']['title'],
413  $inData['meta']['description'],
414  $inData['meta']['notes'],
415  $beUser->user['username'],
416  $beUser->user['realName'],
417  $beUser->user['email']
418  );
419  // Configure which records to export
420  if (is_array($inData['record'])) {
421  foreach ($inData['record'] as $ref) {
422  $rParts = explode(':', $ref);
423  $this->export->export_addRecord($rParts[0], BackendUtility::getRecord($rParts[0], $rParts[1]));
424  }
425  }
426  // Configure which tables to export
427  if (is_array($inData['list'])) {
428  foreach ($inData['list'] as $ref) {
429  $rParts = explode(':', $ref);
430  if ($beUser->check('tables_select', $rParts[0])) {
431  $statement = $this->exec_listQueryPid($rParts[0], $rParts[1], MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1));
432  while ($subTrow = $statement->fetch()) {
433  $this->export->export_addRecord($rParts[0], $subTrow);
434  }
435  }
436  }
437  }
438  // Pagetree
439  if (isset($inData['pagetree']['id'])) {
440  // Based on click-expandable tree
441  $idH = null;
442  if ($inData['pagetree']['levels'] == -1) {
443  $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
444  if ($this->excludeDisabledRecords) {
445  $pagetree->init(BackendUtility::BEenableFields('pages'));
446  }
447  $tree = $pagetree->ext_tree($inData['pagetree']['id'], $this->filterPageIds($this->export->excludeMap));
448  $this->treeHTML = $pagetree->printTree($tree);
449  $idH = $pagetree->buffer_idH;
450  } elseif ($inData['pagetree']['levels'] == -2) {
451  $this->addRecordsForPid($inData['pagetree']['id'], $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
452  } else {
453  // Based on depth
454  // Drawing tree:
455  // If the ID is zero, export root
456  if (!$inData['pagetree']['id'] && $beUser->isAdmin()) {
457  $sPage = [
458  'uid' => 0,
459  'title' => 'ROOT'
460  ];
461  } else {
462  $sPage = BackendUtility::getRecordWSOL('pages', $inData['pagetree']['id'], '*', ' AND ' . $this->perms_clause);
463  }
464  if (is_array($sPage)) {
465  $pid = $inData['pagetree']['id'];
466  $tree = GeneralUtility::makeInstance(PageTreeView::class);
467  $initClause = 'AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap);
468  if ($this->excludeDisabledRecords) {
469  $initClause .= BackendUtility::BEenableFields('pages');
470  }
471  $tree->init($initClause);
472  $HTML = $this->iconFactory->getIconForRecord('pages', $sPage, Icon::SIZE_SMALL)->render();
473  $tree->tree[] = ['row' => $sPage, 'HTML' => $HTML];
474  $tree->buffer_idH = [];
475  if ($inData['pagetree']['levels'] > 0) {
476  $tree->getTree($pid, $inData['pagetree']['levels'], '');
477  }
478  $idH = [];
479  $idH[$pid]['uid'] = $pid;
480  if (!empty($tree->buffer_idH)) {
481  $idH[$pid]['subrow'] = $tree->buffer_idH;
482  }
483  $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
484  $this->treeHTML = $pagetree->printTree($tree->tree);
485  $this->shortcutName .= ' (' . $sPage['title'] . ')';
486  }
487  }
488  // In any case we should have a multi-level array, $idH, with the page structure
489  // here (and the HTML-code loaded into memory for nice display...)
490  if (is_array($idH)) {
491  // Sets the pagetree and gets a 1-dim array in return with the pages (in correct submission order BTW...)
492  $flatList = $this->export->setPageTree($idH);
493  foreach ($flatList as $k => $value) {
494  $this->export->export_addRecord('pages', BackendUtility::getRecord('pages', $k));
495  $this->addRecordsForPid($k, $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
496  }
497  }
498  }
499  // After adding ALL records we set relations:
500  for ($a = 0; $a < 10; $a++) {
501  $addR = $this->export->export_addDBRelations($a);
502  if (empty($addR)) {
503  break;
504  }
505  }
506  // Finally files are added:
507  // MUST be after the DBrelations are set so that files from ALL added records are included!
508  $this->export->export_addFilesFromRelations();
509 
510  $this->export->export_addFilesFromSysFilesRecords();
511 
512  // If the download button is clicked, return file
513  if ($inData['download_export'] || $inData['save_export']) {
514  switch ((string)$inData['filetype']) {
515  case 'xml':
516  $out = $this->export->compileMemoryToFileContent('xml');
517  $fExt = '.xml';
518  break;
519  case 't3d':
520  $this->export->dontCompress = 1;
521  // intentional fall-through
522  // no break
523  default:
524  $out = $this->export->compileMemoryToFileContent();
525  $fExt = ($this->export->doOutputCompress() ? '-z' : '') . '.t3d';
526  }
527  // Filename:
528  $dlFile = $inData['filename'];
529  if (!$dlFile) {
530  $exportName = substr(preg_replace('/[^[:alnum:]_]/', '-', $inData['download_export_name']), 0, 20);
531  $dlFile = 'T3D_' . $exportName . '_' . date('Y-m-d_H-i') . $fExt;
532  }
533 
534  // Export for download:
535  if ($inData['download_export']) {
536  $mimeType = 'application/octet-stream';
537  header('Content-Type: ' . $mimeType);
538  header('Content-Length: ' . strlen($out));
539  header('Content-Disposition: attachment; filename=' . basename($dlFile));
540  echo $out;
541  die;
542  }
543  // Export by saving:
544  if ($inData['save_export']) {
545  $saveFolder = $this->getDefaultImportExportFolder();
546  $lang = $this->getLanguageService();
547  if ($saveFolder !== false && $saveFolder->checkActionPermission('write')) {
548  $temporaryFileName = GeneralUtility::tempnam('export');
549  file_put_contents($temporaryFileName, $out);
550  $file = $saveFolder->addFile($temporaryFileName, $dlFile, 'replace');
551  if ($saveFilesOutsideExportFile) {
552  $filesFolderName = $dlFile . '.files';
553  $filesFolder = $saveFolder->createFolder($filesFolderName);
554  $temporaryFolderForExport = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->export->getTemporaryFilesPathForExport());
555  $temporaryFilesForExport = $temporaryFolderForExport->getFiles();
556  foreach ($temporaryFilesForExport as $temporaryFileForExport) {
557  $filesFolder->getStorage()->moveFile($temporaryFileForExport, $filesFolder);
558  }
559  $temporaryFolderForExport->delete();
560  }
561 
563  $flashMessage = GeneralUtility::makeInstance(
564  FlashMessage::class,
565  sprintf($lang->getLL('exportdata_savedInSBytes'), $file->getPublicUrl(), GeneralUtility::formatSize(strlen($out))),
566  $lang->getLL('exportdata_savedFile'),
568  );
569  } else {
571  $flashMessage = GeneralUtility::makeInstance(
572  FlashMessage::class,
573  sprintf($lang->getLL('exportdata_badPathS'), $saveFolder->getPublicUrl()),
574  $lang->getLL('exportdata_problemsSavingFile'),
576  );
577  }
579  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
581  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
582  $defaultFlashMessageQueue->enqueue($flashMessage);
583  }
584  }
585 
586  $this->makeConfigurationForm($inData);
587 
588  $this->makeSaveForm($inData);
589 
590  $this->makeAdvancedOptionsForm($inData);
591 
592  $this->standaloneView->assign('errors', $this->export->errorLog);
593 
594  // Generate overview:
595  $this->standaloneView->assign(
596  'contentOverview',
597  $this->export->displayContentOverview()
598  );
599  }
600 
608  public function addRecordsForPid($k, $tables, $maxNumber)
609  {
610  if (!is_array($tables)) {
611  return;
612  }
613  foreach ($GLOBALS['TCA'] as $table => $value) {
614  if ($table !== 'pages' && (in_array($table, $tables) || in_array('_ALL', $tables))) {
615  if ($this->getBackendUser()->check('tables_select', $table) && !$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
616  $statement = $this->exec_listQueryPid($table, $k, MathUtility::forceIntegerInRange($maxNumber, 1));
617  while ($subTrow = $statement->fetch()) {
618  $this->export->export_addRecord($table, $subTrow);
619  }
620  }
621  }
622  }
623  }
624 
633  public function exec_listQueryPid($table, $pid, $limit)
634  {
635  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
636 
637  $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ?: $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
638  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
639 
640  if ($this->excludeDisabledRecords === false) {
641  $queryBuilder->getRestrictions()
642  ->removeAll()
643  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
644  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
645  }
646 
647  $queryBuilder->select('*')
648  ->from($table)
649  ->where(
650  $queryBuilder->expr()->eq(
651  'pid',
652  $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)
653  )
654  )
655  ->setMaxResults($limit);
656 
657  foreach (QueryHelper::parseOrderBy((string)$orderBy) as $orderPair) {
658  list($fieldName, $order) = $orderPair;
659  $queryBuilder->addOrderBy($fieldName, $order);
660  }
661 
662  $statement = $queryBuilder->execute();
663 
664  // Warning about hitting limit:
665  if ($statement->rowCount() == $limit) {
666  $limitWarning = sprintf($this->lang->getLL('makeconfig_anSqlQueryReturned'), $limit);
668  $flashMessage = GeneralUtility::makeInstance(
669  FlashMessage::class,
670  $this->lang->getLL('execlistqu_maxNumberLimit'),
671  $limitWarning,
673  );
675  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
677  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
678  $defaultFlashMessageQueue->enqueue($flashMessage);
679  }
680 
681  return $statement;
682  }
683 
689  public function makeConfigurationForm($inData)
690  {
691  $nameSuggestion = '';
692  // Page tree export options:
693  if (isset($inData['pagetree']['id'])) {
694  $this->standaloneView->assign('treeHTML', $this->treeHTML);
695 
696  $opt = [
697  '-2' => $this->lang->getLL('makeconfig_tablesOnThisPage'),
698  '-1' => $this->lang->getLL('makeconfig_expandedTree'),
699  '0' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
700  '1' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
701  '2' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
702  '3' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
703  '4' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
704  '999' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
705  ];
706  $this->standaloneView->assign('levelSelectOptions', $opt);
707  $this->standaloneView->assign('tableSelectOptions', $this->getTableSelectOptions('pages'));
708  $nameSuggestion .= 'tree_PID' . $inData['pagetree']['id'] . '_L' . $inData['pagetree']['levels'];
709  }
710  // Single record export:
711  if (is_array($inData['record'])) {
712  $records = [];
713  foreach ($inData['record'] as $ref) {
714  $rParts = explode(':', $ref);
715  $tName = $rParts[0];
716  $rUid = $rParts[1];
717  $nameSuggestion .= $tName . '_' . $rUid;
718  $rec = BackendUtility::getRecordWSOL($tName, $rUid);
719  if (!empty($rec)) {
720  $records[] = [
721  'icon' => $this->iconFactory->getIconForRecord($tName, $rec, Icon::SIZE_SMALL)->render(),
722  'title' => BackendUtility::getRecordTitle($tName, $rec, true),
723  'tableName' => $tName,
724  'recordUid' => $rUid
725  ];
726  }
727  }
728  $this->standaloneView->assign('records', $records);
729  }
730  // Single tables/pids:
731  if (is_array($inData['list'])) {
732 
733  // Display information about pages from which the export takes place
734  $tableList = [];
735  foreach ($inData['list'] as $reference) {
736  $referenceParts = explode(':', $reference);
737  $tableName = $referenceParts[0];
738  if ($this->getBackendUser()->check('tables_select', $tableName)) {
739  // If the page is actually the root, handle it differently
740  // NOTE: we don't compare integers, because the number actually comes from the split string above
741  if ($referenceParts[1] === '0') {
742  $iconAndTitle = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
743  } else {
744  $record = BackendUtility::getRecordWSOL('pages', $referenceParts[1]);
745  $iconAndTitle = $this->iconFactory->getIconForRecord('pages', $record, Icon::SIZE_SMALL)->render()
746  . BackendUtility::getRecordTitle('pages', $record, true);
747  }
748 
749  $tableList[] = [
750  'iconAndTitle' => sprintf($this->lang->getLL('makeconfig_tableListEntry'), $tableName, $iconAndTitle),
751  'reference' => $reference
752  ];
753  }
754  }
755  $this->standaloneView->assign('tableList', $tableList);
756  }
757 
758  $this->standaloneView->assign('externalReferenceTableSelectOptions', $this->getTableSelectOptions());
759  $this->standaloneView->assign('externalStaticTableSelectOptions', $this->getTableSelectOptions());
760  $this->standaloneView->assign('nameSuggestion', $nameSuggestion);
761  }
762 
769  public function makeAdvancedOptionsForm($inData)
770  {
772  $loadedExtensions = array_combine($loadedExtensions, $loadedExtensions);
773  $this->standaloneView->assign('extensions', $loadedExtensions);
774  $this->standaloneView->assign('inData', $inData);
775  }
776 
782  public function makeSaveForm($inData)
783  {
784  $opt = $this->presetRepository->getPresets((int)$inData['pagetree']['id']);
785 
786  $this->standaloneView->assign('presetSelectOptions', $opt);
787 
788  $saveFolder = $this->getDefaultImportExportFolder();
789  if ($saveFolder) {
790  $this->standaloneView->assign('saveFolder', $saveFolder->getCombinedIdentifier());
791  }
792 
793  // Add file options:
794  $opt = [];
795  if ($this->export->compress) {
796  $opt['t3d_compressed'] = $this->lang->getLL('makesavefo_t3dFileCompressed');
797  }
798  $opt['t3d'] = $this->lang->getLL('makesavefo_t3dFile');
799  $opt['xml'] = $this->lang->getLL('makesavefo_xml');
800 
801  $this->standaloneView->assign('filetypeSelectOptions', $opt);
802 
803  $fileName = '';
804  if ($saveFolder) {
805  $this->standaloneView->assign('saveFolder', $saveFolder->getPublicUrl());
806  $this->standaloneView->assign('hasSaveFolder', true);
807  }
808  $this->standaloneView->assign('fileName', $fileName);
809  }
810 
811  /**************************
812  * IMPORT FUNCTIONS
813  **************************/
814 
823  public function importData($inData)
824  {
825  $access = is_array($this->pageinfo) ? 1 : 0;
826  $beUser = $this->getBackendUser();
827  if ($this->id && $access || $beUser->user['admin'] && !$this->id) {
828  if ($beUser->user['admin'] && !$this->id) {
829  $this->pageinfo = ['title' => '[root-level]', 'uid' => 0, 'pid' => 0];
830  }
831  if ($inData['new_import']) {
832  unset($inData['import_mode']);
833  }
835  $import = GeneralUtility::makeInstance(Import::class);
836  $import->init();
837  $import->update = $inData['do_update'];
838  $import->import_mode = $inData['import_mode'];
839  $import->enableLogging = $inData['enableLogging'];
840  $import->global_ignore_pid = $inData['global_ignore_pid'];
841  $import->force_all_UIDS = $inData['force_all_UIDS'];
842  $import->showDiff = !$inData['notShowDiff'];
843  $import->allowPHPScripts = $inData['allowPHPScripts'];
844  $import->softrefInputValues = $inData['softrefInputValues'];
845 
846  // OUTPUT creation:
847 
848  // Make input selector:
849  // must have trailing slash.
850  $path = $this->getDefaultImportExportFolder();
851  $exportFiles = $this->getExportFiles();
852 
853  $this->shortcutName .= ' (' . $this->pageinfo['title'] . ')';
854 
855  // Configuration
856  $selectOptions = [''];
857  foreach ($exportFiles as $file) {
858  $selectOptions[$file->getCombinedIdentifier()] = $file->getPublicUrl();
859  }
860 
861  $this->standaloneView->assign('import', $import);
862  $this->standaloneView->assign('inData', $inData);
863  $this->standaloneView->assign('fileSelectOptions', $selectOptions);
864 
865  if ($path) {
866  $this->standaloneView->assign('importPath', sprintf($this->lang->getLL('importdata_fromPathS'), $path->getCombinedIdentifier()));
867  } else {
868  $this->standaloneView->assign('importPath', $this->lang->getLL('importdata_no_default_upload_folder'));
869  }
870  $this->standaloneView->assign('isAdmin', $beUser->isAdmin());
871 
872  // Upload file:
873  $tempFolder = $this->getDefaultImportExportFolder();
874  if ($tempFolder) {
875  $this->standaloneView->assign('tempFolder', $tempFolder->getCombinedIdentifier());
876  $this->standaloneView->assign('hasTempUploadFolder', true);
877  if (GeneralUtility::_POST('_upload')) {
878  $this->standaloneView->assign('submitted', GeneralUtility::_POST('_upload'));
879  $this->standaloneView->assign('noFileUploaded', $this->fileProcessor->internalUploadMap[1]);
880  if ($this->uploadedFiles[0]) {
881  $this->standaloneView->assign('uploadedFile', $this->uploadedFiles[0]->getName());
882  }
883  }
884  }
885 
886  // Perform import or preview depending:
887  $inFile = $this->getFile($inData['file']);
888  if ($inFile !== null && $inFile->exists()) {
889  $this->standaloneView->assign('metaDataInFileExists', true);
890  $importInhibitedMessages = [];
891  if ($import->loadFile($inFile->getForLocalProcessing(false), 1)) {
892  $importInhibitedMessages = $import->checkImportPrerequisites();
893  if ($inData['import_file']) {
894  if (empty($importInhibitedMessages)) {
895  $import->importData($this->id);
896  BackendUtility::setUpdateSignal('updatePageTree');
897  }
898  }
899  $import->display_import_pid_record = $this->pageinfo;
900  $this->standaloneView->assign('contentOverview', $import->displayContentOverview());
901  }
902  // Compile messages which are inhibiting a proper import and add them to output.
903  if (!empty($importInhibitedMessages)) {
904  $flashMessageQueue = GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier('impexp.errors');
905  foreach ($importInhibitedMessages as $message) {
906  $flashMessageQueue->addMessage(GeneralUtility::makeInstance(
907  FlashMessage::class,
908  $message,
909  '',
911  ));
912  }
913  }
914  }
915 
916  $this->standaloneView->assign('errors', $import->errorLog);
917  }
918  }
919 
920  /****************************
921  * Helper functions
922  ****************************/
923 
931  protected function getDefaultImportExportFolder()
932  {
933  $defaultImportExportFolder = null;
934 
935  $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder();
936  if ($defaultTemporaryFolder !== null) {
937  $importExportFolderName = 'importexport';
938  $createFolder = !$defaultTemporaryFolder->hasFolder($importExportFolderName);
939  if ($createFolder === true) {
940  try {
941  $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName);
942  } catch (Exception $folderAccessException) {
943  }
944  } else {
945  $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName);
946  }
947  }
948 
949  return $defaultImportExportFolder;
950  }
951 
958  public function checkUpload()
959  {
960  $file = GeneralUtility::_GP('file');
961  // Initializing:
962  $this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
963  $this->fileProcessor->setActionPermissions();
964  $conflictMode = empty(GeneralUtility::_GP('overwriteExistingFiles')) ? DuplicationBehavior::__default : DuplicationBehavior::REPLACE;
965  $this->fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::cast($conflictMode));
966  $this->fileProcessor->start($file);
967  $result = $this->fileProcessor->processData();
968  if (!empty($result['upload'])) {
969  foreach ($result['upload'] as $uploadedFiles) {
970  $this->uploadedFiles += $uploadedFiles;
971  }
972  }
973  }
974 
981  public function getTableSelectOptions($excludeList = '')
982  {
983  $optValues = [];
984  if (!GeneralUtility::inList($excludeList, '_ALL')) {
985  $optValues['_ALL'] = '[' . $this->lang->getLL('ALL_tables') . ']';
986  }
987  foreach ($GLOBALS['TCA'] as $table => $_) {
988  if ($this->getBackendUser()->check('tables_select', $table) && !GeneralUtility::inList($excludeList, $table)) {
989  $optValues[$table] = $table;
990  }
991  }
992  return $optValues;
993  }
994 
1002  public function filterPageIds($exclude)
1003  {
1004  // Get keys:
1005  $exclude = array_keys($exclude);
1006  // Traverse
1007  $pageIds = [];
1008  foreach ($exclude as $element) {
1009  list($table, $uid) = explode(':', $element);
1010  if ($table === 'pages') {
1011  $pageIds[] = (int)$uid;
1012  }
1013  }
1014  // Add to clause:
1015  if (!empty($pageIds)) {
1016  return ' AND uid NOT IN (' . implode(',', $pageIds) . ')';
1017  }
1018  return '';
1019  }
1020 
1024  protected function getBackendUser()
1025  {
1026  return $GLOBALS['BE_USER'];
1027  }
1028 
1032  protected function getLanguageService()
1033  {
1034  return $GLOBALS['LANG'];
1035  }
1036 
1043  protected function getExportFiles()
1044  {
1045  $exportFiles = [];
1046 
1047  $folder = $this->getDefaultImportExportFolder();
1048  if ($folder !== null) {
1049 
1051  $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
1052  $filter->setAllowedFileExtensions(['t3d', 'xml']);
1053  $folder->getStorage()->addFileAndFolderNameFilter([$filter, 'filterFileList']);
1054 
1055  $exportFiles = $folder->getFiles();
1056  }
1057 
1058  return $exportFiles;
1059  }
1060 
1067  protected function getFile($combinedIdentifier)
1068  {
1069  try {
1070  $file = ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
1071  } catch (\Exception $exception) {
1072  $file = null;
1073  }
1074 
1075  return $file;
1076  }
1077 }
static getRecordWSOL( $table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static readPageAccess($id, $perms_clause)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static BEenableFields($table, $inv=false)
static viewOnClick( $pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static makeInstance($className,... $constructorArguments)
static tempnam($filePrefix, $fileSuffix='')
static setUpdateSignal($set='', $params='')
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static formatSize($sizeInBytes, $labels='', $base=0)
mainAction(ServerRequestInterface $request, ResponseInterface $response)
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']