| Total Complexity | 266 |
| Total Lines | 1760 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like ImportExport often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ImportExport, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 44 | abstract class ImportExport |
||
| 45 | { |
||
| 46 | /** |
||
| 47 | * Whether "import" or "export" mode of object. |
||
| 48 | * |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | protected $mode = ''; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * A WHERE clause for selection records from the pages table based on read-permissions of the current backend user. |
||
| 55 | * |
||
| 56 | * @var string |
||
| 57 | */ |
||
| 58 | protected $permsClause; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Root page of import or export page tree |
||
| 62 | * |
||
| 63 | * @var int |
||
| 64 | */ |
||
| 65 | protected $pid = -1; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Root page record of import or of export page tree |
||
| 69 | */ |
||
| 70 | protected ?array $pidRecord = null; |
||
| 71 | |||
| 72 | /** |
||
| 73 | * If set, static relations (not exported) will be shown in preview as well |
||
| 74 | * |
||
| 75 | * @var bool |
||
| 76 | */ |
||
| 77 | protected $showStaticRelations = false; |
||
| 78 | |||
| 79 | /** |
||
| 80 | * Updates all records that has same UID instead of creating new! |
||
| 81 | * |
||
| 82 | * @var bool |
||
| 83 | */ |
||
| 84 | protected $update = false; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Set by importData() when an import is started. |
||
| 88 | * |
||
| 89 | * @var bool |
||
| 90 | */ |
||
| 91 | protected $doesImport = false; |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Setting the import mode for specific import records. |
||
| 95 | * Available options are: force_uid, as_new, exclude, ignore_pid, respect_pid |
||
| 96 | * |
||
| 97 | * @var array |
||
| 98 | */ |
||
| 99 | protected $importMode = []; |
||
| 100 | |||
| 101 | /** |
||
| 102 | * If set, PID correct is ignored globally |
||
| 103 | * |
||
| 104 | * @var bool |
||
| 105 | */ |
||
| 106 | protected $globalIgnorePid = false; |
||
| 107 | |||
| 108 | /** |
||
| 109 | * If set, all UID values are forced! (update or import) |
||
| 110 | * |
||
| 111 | * @var bool |
||
| 112 | */ |
||
| 113 | protected $forceAllUids = false; |
||
| 114 | |||
| 115 | /** |
||
| 116 | * If set, a diff-view column is added to the preview. |
||
| 117 | * |
||
| 118 | * @var bool |
||
| 119 | */ |
||
| 120 | protected $showDiff = false; |
||
| 121 | |||
| 122 | /** |
||
| 123 | * Array of values to substitute in editable soft references. |
||
| 124 | * |
||
| 125 | * @var array |
||
| 126 | */ |
||
| 127 | protected $softrefInputValues = []; |
||
| 128 | |||
| 129 | /** |
||
| 130 | * Mapping between the fileID from import memory and the final filenames they are written to. |
||
| 131 | * |
||
| 132 | * @var array |
||
| 133 | */ |
||
| 134 | protected $fileIdMap = []; |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Add tables names here which should not be exported with the file. |
||
| 138 | * (Where relations should be mapped to same UIDs in target system). |
||
| 139 | * |
||
| 140 | * @var array |
||
| 141 | */ |
||
| 142 | protected $relStaticTables = []; |
||
| 143 | |||
| 144 | /** |
||
| 145 | * Exclude map. Keys are table:uid pairs and if set, records are not added to the export. |
||
| 146 | * |
||
| 147 | * @var array |
||
| 148 | */ |
||
| 149 | protected $excludeMap = []; |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Soft reference token ID modes. |
||
| 153 | * |
||
| 154 | * @var array |
||
| 155 | */ |
||
| 156 | protected $softrefCfg = []; |
||
| 157 | |||
| 158 | /** |
||
| 159 | * Listing extension dependencies. |
||
| 160 | * |
||
| 161 | * @var array |
||
| 162 | */ |
||
| 163 | protected $extensionDependencies = []; |
||
| 164 | |||
| 165 | /** |
||
| 166 | * After records are written this array is filled with [table][original_uid] = [new_uid] |
||
| 167 | * |
||
| 168 | * @var array |
||
| 169 | */ |
||
| 170 | protected $importMapId = []; |
||
| 171 | |||
| 172 | /** |
||
| 173 | * Error log. |
||
| 174 | * |
||
| 175 | * @var array |
||
| 176 | */ |
||
| 177 | protected $errorLog = []; |
||
| 178 | |||
| 179 | /** |
||
| 180 | * Cache for record paths |
||
| 181 | * |
||
| 182 | * @var array |
||
| 183 | */ |
||
| 184 | protected $cacheGetRecordPath = []; |
||
| 185 | |||
| 186 | /** |
||
| 187 | * Internal import/export memory |
||
| 188 | * |
||
| 189 | * @var array |
||
| 190 | */ |
||
| 191 | protected $dat = []; |
||
| 192 | |||
| 193 | /** |
||
| 194 | * File processing object |
||
| 195 | * |
||
| 196 | * @var ExtendedFileUtility |
||
| 197 | */ |
||
| 198 | protected $fileProcObj; |
||
| 199 | |||
| 200 | /** |
||
| 201 | * @var DiffUtility |
||
| 202 | */ |
||
| 203 | protected $diffUtility; |
||
| 204 | |||
| 205 | /** |
||
| 206 | * @var array |
||
| 207 | */ |
||
| 208 | protected $remainHeader = []; |
||
| 209 | |||
| 210 | /** |
||
| 211 | * @var LanguageService |
||
| 212 | */ |
||
| 213 | protected $lang; |
||
| 214 | |||
| 215 | /** |
||
| 216 | * @var IconFactory |
||
| 217 | */ |
||
| 218 | protected $iconFactory; |
||
| 219 | |||
| 220 | /** |
||
| 221 | * Name of the "fileadmin" folder where files for export/import should be located |
||
| 222 | * |
||
| 223 | * @var string |
||
| 224 | */ |
||
| 225 | protected $fileadminFolderName = ''; |
||
| 226 | |||
| 227 | protected ?string $temporaryFolderName = null; |
||
| 228 | protected ?Folder $defaultImportExportFolder = null; |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Flag to control whether all disabled records and their children are excluded (true) or included (false). Defaults |
||
| 232 | * to the old behaviour of including everything. |
||
| 233 | * |
||
| 234 | * @var bool |
||
| 235 | */ |
||
| 236 | protected $excludeDisabledRecords = false; |
||
| 237 | |||
| 238 | /** |
||
| 239 | * Array of currently registered storage objects |
||
| 240 | * |
||
| 241 | * @var ResourceStorage[] |
||
| 242 | */ |
||
| 243 | protected $storages = []; |
||
| 244 | |||
| 245 | /** |
||
| 246 | * Array of currently registered storage objects available for importing files to |
||
| 247 | * |
||
| 248 | * @var ResourceStorage[] |
||
| 249 | */ |
||
| 250 | protected $storagesAvailableForImport = []; |
||
| 251 | |||
| 252 | /** |
||
| 253 | * Currently registered default storage object |
||
| 254 | */ |
||
| 255 | protected ?ResourceStorage $defaultStorage = null; |
||
| 256 | |||
| 257 | /** |
||
| 258 | * @var StorageRepository |
||
| 259 | */ |
||
| 260 | protected $storageRepository; |
||
| 261 | |||
| 262 | /** |
||
| 263 | * The constructor |
||
| 264 | */ |
||
| 265 | public function __construct() |
||
| 266 | { |
||
| 267 | $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class); |
||
| 268 | $this->lang = $this->getLanguageService(); |
||
| 269 | $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf'); |
||
| 270 | $this->permsClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW); |
||
| 271 | |||
| 272 | $this->fetchStorages(); |
||
| 273 | } |
||
| 274 | |||
| 275 | /** |
||
| 276 | * Fetch all available file storages and index by storage UID |
||
| 277 | * |
||
| 278 | * Note: It also creates a default storage record if the database table sys_file_storage is empty, |
||
| 279 | * e.g. during tests. |
||
| 280 | */ |
||
| 281 | protected function fetchStorages(): void |
||
| 282 | { |
||
| 283 | $this->storages = []; |
||
| 284 | $this->storagesAvailableForImport = []; |
||
| 285 | $this->defaultStorage = null; |
||
| 286 | |||
| 287 | $this->getStorageRepository()->flush(); |
||
| 288 | |||
| 289 | $storages = $this->getStorageRepository()->findAll(); |
||
| 290 | // @todo: Why by reference here? Test ImagesWithStoragesTest::importMultipleImagesWithMultipleStorages fails otherwise |
||
| 291 | foreach ($storages as &$storage) { |
||
| 292 | $this->storages[$storage->getUid()] = $storage; |
||
| 293 | if ($storage->isOnline() && $storage->isWritable() && $storage->getDriverType() === 'Local') { |
||
| 294 | $this->storagesAvailableForImport[$storage->getUid()] = $storage; |
||
| 295 | } |
||
| 296 | if ($this->defaultStorage === null && $storage->isDefault()) { |
||
| 297 | $this->defaultStorage = $storage; |
||
| 298 | } |
||
| 299 | } |
||
| 300 | } |
||
| 301 | |||
| 302 | /******************************************************** |
||
| 303 | * Visual rendering of import/export memory, $this->dat |
||
| 304 | ********************************************************/ |
||
| 305 | |||
| 306 | /** |
||
| 307 | * Displays a preview of the import or export. |
||
| 308 | * |
||
| 309 | * @return array The preview data |
||
| 310 | */ |
||
| 311 | public function renderPreview(): array |
||
| 312 | { |
||
| 313 | // @todo: Why is this done? |
||
| 314 | unset($this->dat['files']); |
||
| 315 | |||
| 316 | $previewData = [ |
||
| 317 | 'update' => $this->update, |
||
| 318 | 'showDiff' => $this->showDiff, |
||
| 319 | 'insidePageTree' => [], |
||
| 320 | 'outsidePageTree' => [], |
||
| 321 | ]; |
||
| 322 | |||
| 323 | if (!isset($this->dat['header']['pagetree']) && !isset($this->dat['header']['records'])) { |
||
| 324 | return $previewData; |
||
| 325 | } |
||
| 326 | |||
| 327 | // Traverse header: |
||
| 328 | $this->remainHeader = $this->dat['header']; |
||
| 329 | |||
| 330 | // Preview of the page tree to be exported |
||
| 331 | if (is_array($this->dat['header']['pagetree'] ?? null)) { |
||
| 332 | $this->traversePageTree($this->dat['header']['pagetree'], $previewData['insidePageTree']); |
||
| 333 | foreach ($previewData['insidePageTree'] as &$line) { |
||
| 334 | $line['controls'] = $this->renderControls($line); |
||
| 335 | $line['message'] = (($line['msg'] ?? '') && !$this->doesImport ? '<span class="text-danger">' . htmlspecialchars($line['msg']) . '</span>' : ''); |
||
| 336 | } |
||
| 337 | } |
||
| 338 | |||
| 339 | // Preview the remaining records that were not included in the page tree |
||
| 340 | if (is_array($this->remainHeader['records'] ?? null)) { |
||
| 341 | if (is_array($this->remainHeader['records']['pages'] ?? null)) { |
||
| 342 | $this->traversePageRecords($this->remainHeader['records']['pages'], $previewData['outsidePageTree']); |
||
| 343 | } |
||
| 344 | $this->traverseAllRecords($this->remainHeader['records'], $previewData['outsidePageTree']); |
||
| 345 | foreach ($previewData['outsidePageTree'] as &$line) { |
||
| 346 | $line['controls'] = $this->renderControls($line); |
||
| 347 | $line['message'] = (($line['msg'] ?? '') && !$this->doesImport ? '<span class="text-danger">' . htmlspecialchars($line['msg']) . '</span>' : ''); |
||
| 348 | } |
||
| 349 | } |
||
| 350 | |||
| 351 | return $previewData; |
||
| 352 | } |
||
| 353 | |||
| 354 | /** |
||
| 355 | * Go through page tree for display |
||
| 356 | * |
||
| 357 | * @param array<int, array> $pageTree Page tree array with uid/subrow (from ->dat[header][pagetree]) |
||
| 358 | * @param array $lines Output lines array |
||
| 359 | * @param int $indent Indentation level |
||
| 360 | */ |
||
| 361 | protected function traversePageTree(array $pageTree, array &$lines, int $indent = 0): void |
||
| 362 | { |
||
| 363 | foreach ($pageTree as $pageUid => $page) { |
||
| 364 | if ($this->excludeDisabledRecords === true && $this->isRecordDisabled('pages', $pageUid)) { |
||
| 365 | $this->excludePageAndRecords($pageUid, $page); |
||
| 366 | continue; |
||
| 367 | } |
||
| 368 | |||
| 369 | // Add page |
||
| 370 | $this->addRecord('pages', $pageUid, $lines, $indent); |
||
| 371 | |||
| 372 | // Add records |
||
| 373 | if (is_array($this->dat['header']['pid_lookup'][$pageUid] ?? null)) { |
||
| 374 | foreach ($this->dat['header']['pid_lookup'][$pageUid] as $table => $records) { |
||
| 375 | $table = (string)$table; |
||
| 376 | if ($table !== 'pages') { |
||
| 377 | foreach (array_keys($records) as $uid) { |
||
| 378 | $this->addRecord($table, (int)$uid, $lines, $indent + 2); |
||
| 379 | } |
||
| 380 | } |
||
| 381 | } |
||
| 382 | unset($this->remainHeader['pid_lookup'][$pageUid]); |
||
| 383 | } |
||
| 384 | |||
| 385 | // Add subtree |
||
| 386 | if (is_array($page['subrow'] ?? null)) { |
||
| 387 | $this->traversePageTree($page['subrow'], $lines, $indent + 2); |
||
| 388 | } |
||
| 389 | } |
||
| 390 | } |
||
| 391 | |||
| 392 | /** |
||
| 393 | * Test whether a record is disabled (e.g. hidden) |
||
| 394 | * |
||
| 395 | * @param string $table Name of the records' database table |
||
| 396 | * @param int $uid Database uid of the record |
||
| 397 | * @return bool true if the record is disabled, false otherwise |
||
| 398 | */ |
||
| 399 | protected function isRecordDisabled(string $table, int $uid): bool |
||
| 400 | { |
||
| 401 | return (bool)($this->dat['records'][$table . ':' . $uid]['data'][ |
||
| 402 | $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'] ?? '' |
||
| 403 | ] ?? false); |
||
| 404 | } |
||
| 405 | |||
| 406 | /** |
||
| 407 | * Exclude a page, its sub pages (recursively) and records placed in them from this import/export |
||
| 408 | * |
||
| 409 | * @param int $pageUid Uid of the page to exclude |
||
| 410 | * @param array $page Page array with uid/subrow (from ->dat[header][pagetree]) |
||
| 411 | */ |
||
| 412 | protected function excludePageAndRecords(int $pageUid, array $page): void |
||
| 413 | { |
||
| 414 | // Exclude page |
||
| 415 | unset($this->remainHeader['records']['pages'][$pageUid]); |
||
| 416 | |||
| 417 | // Exclude records |
||
| 418 | if (is_array($this->dat['header']['pid_lookup'][$pageUid] ?? null)) { |
||
| 419 | foreach ($this->dat['header']['pid_lookup'][$pageUid] as $table => $records) { |
||
| 420 | if ($table !== 'pages') { |
||
| 421 | foreach (array_keys($records) as $uid) { |
||
| 422 | unset($this->remainHeader['records'][$table][$uid]); |
||
| 423 | } |
||
| 424 | } |
||
| 425 | } |
||
| 426 | unset($this->remainHeader['pid_lookup'][$pageUid]); |
||
| 427 | } |
||
| 428 | |||
| 429 | // Exclude subtree |
||
| 430 | if (is_array($page['subrow'] ?? null)) { |
||
| 431 | foreach ($page['subrow'] as $subPageUid => $subPage) { |
||
| 432 | $this->excludePageAndRecords($subPageUid, $subPage); |
||
| 433 | } |
||
| 434 | } |
||
| 435 | } |
||
| 436 | |||
| 437 | /** |
||
| 438 | * Go through remaining pages (not in tree) |
||
| 439 | * |
||
| 440 | * @param array<int, array> $pageTree Page tree array with uid/subrow (from ->dat[header][pagetree]) |
||
| 441 | * @param array $lines Output lines array |
||
| 442 | */ |
||
| 443 | protected function traversePageRecords(array $pageTree, array &$lines): void |
||
| 444 | { |
||
| 445 | foreach ($pageTree as $pageUid => $_) { |
||
| 446 | // Add page |
||
| 447 | $this->addRecord('pages', (int)$pageUid, $lines, 0, true); |
||
| 448 | |||
| 449 | // Add records |
||
| 450 | if (is_array($this->dat['header']['pid_lookup'][$pageUid] ?? null)) { |
||
| 451 | foreach ($this->dat['header']['pid_lookup'][$pageUid] as $table => $records) { |
||
| 452 | if ($table !== 'pages') { |
||
| 453 | foreach (array_keys($records) as $uid) { |
||
| 454 | $this->addRecord((string)$table, (int)$uid, $lines, 2); |
||
| 455 | } |
||
| 456 | } |
||
| 457 | } |
||
| 458 | unset($this->remainHeader['pid_lookup'][$pageUid]); |
||
| 459 | } |
||
| 460 | } |
||
| 461 | } |
||
| 462 | |||
| 463 | /** |
||
| 464 | * Go through ALL records (if the pages are displayed first, those will not be among these!) |
||
| 465 | * |
||
| 466 | * @param array $pageTree Page tree array with uid/subrow (from ->dat[header][pagetree]) |
||
| 467 | * @param array $lines Output lines array |
||
| 468 | */ |
||
| 469 | protected function traverseAllRecords(array $pageTree, array &$lines): void |
||
| 470 | { |
||
| 471 | foreach ($pageTree as $table => $records) { |
||
| 472 | $this->addGeneralErrorsByTable($table); |
||
| 473 | if ($table !== 'pages') { |
||
| 474 | foreach (array_keys($records) as $uid) { |
||
| 475 | $this->addRecord((string)$table, (int)$uid, $lines, 0, true); |
||
| 476 | } |
||
| 477 | } |
||
| 478 | } |
||
| 479 | } |
||
| 480 | |||
| 481 | /** |
||
| 482 | * Log general error message for a given table |
||
| 483 | * |
||
| 484 | * @param string $table database table name |
||
| 485 | */ |
||
| 486 | protected function addGeneralErrorsByTable(string $table): void |
||
| 487 | { |
||
| 488 | if ($this->update && $table === 'sys_file') { |
||
| 489 | $this->addError('Updating sys_file records is not supported! They will be imported as new records!'); |
||
| 490 | } |
||
| 491 | if ($this->forceAllUids && $table === 'sys_file') { |
||
| 492 | $this->addError('Forcing uids of sys_file records is not supported! They will be imported as new records!'); |
||
| 493 | } |
||
| 494 | } |
||
| 495 | |||
| 496 | /** |
||
| 497 | * Add a record, its relations and soft references, to the preview |
||
| 498 | * |
||
| 499 | * @param string $table Table name |
||
| 500 | * @param int $uid Record uid |
||
| 501 | * @param array $lines Output lines array |
||
| 502 | * @param int $indent Indentation level |
||
| 503 | * @param bool $checkImportInPidRecord If you want import validation, you can set this so it checks if the import can take place on the specified page. |
||
| 504 | */ |
||
| 505 | protected function addRecord(string $table, int $uid, array &$lines, int $indent, bool $checkImportInPidRecord = false): void |
||
| 506 | { |
||
| 507 | $record = $this->dat['header']['records'][$table][$uid] ?? null; |
||
| 508 | unset($this->remainHeader['records'][$table][$uid]); |
||
| 509 | if (!is_array($record) && !($table === 'pages' && $uid === 0)) { |
||
| 510 | $this->addError('MISSING RECORD: ' . $table . ':' . $uid); |
||
| 511 | } |
||
| 512 | |||
| 513 | // Create record information for preview |
||
| 514 | $line = []; |
||
| 515 | $line['ref'] = $table . ':' . $uid; |
||
| 516 | $line['type'] = 'record'; |
||
| 517 | $line['msg'] = ''; |
||
| 518 | if ($table === '_SOFTREF_') { |
||
| 519 | // Record is a soft reference |
||
| 520 | $line['preCode'] = $this->renderIndent($indent); |
||
| 521 | $line['title'] = '<em>' . htmlspecialchars($this->lang->getLL('impexpcore_singlereco_softReferencesFiles')) . '</em>'; |
||
| 522 | } elseif (!isset($GLOBALS['TCA'][$table])) { |
||
| 523 | // Record is of unknown table |
||
| 524 | $line['preCode'] = $this->renderIndent($indent); |
||
| 525 | $line['title'] = '<em>' . htmlspecialchars((string)$record['title']) . '</em>'; |
||
| 526 | $line['msg'] = 'UNKNOWN TABLE "' . $line['ref'] . '"'; |
||
| 527 | } else { |
||
| 528 | $pidRecord = $this->getPidRecord(); |
||
| 529 | $icon = $this->iconFactory->getIconForRecord( |
||
| 530 | $table, |
||
| 531 | (array)($this->dat['records'][$table . ':' . $uid]['data'] ?? []), |
||
| 532 | Icon::SIZE_SMALL |
||
| 533 | )->render(); |
||
| 534 | $line['preCode'] = sprintf( |
||
| 535 | '%s<span title="%s">%s</span>', |
||
| 536 | $this->renderIndent($indent), |
||
| 537 | htmlspecialchars($line['ref']), |
||
| 538 | $icon |
||
| 539 | ); |
||
| 540 | $line['title'] = htmlspecialchars($record['title'] ?? ''); |
||
| 541 | // Link to page view |
||
| 542 | if ($table === 'pages') { |
||
| 543 | $viewID = $this->mode === 'export' ? $uid : ($this->doesImport ? ($this->importMapId['pages'][$uid] ?? 0) : 0); |
||
| 544 | if ($viewID) { |
||
| 545 | $attributes = PreviewUriBuilder::create($viewID)->serializeDispatcherAttributes(); |
||
| 546 | $line['title'] = sprintf('<a href="#" %s>%s</a>', $attributes, $line['title']); |
||
| 547 | } |
||
| 548 | } |
||
| 549 | $line['active'] = !$this->isRecordDisabled($table, $uid) ? 'active' : 'hidden'; |
||
| 550 | if ($this->mode === 'import' && $pidRecord !== null) { |
||
| 551 | if ($checkImportInPidRecord) { |
||
| 552 | if (!$this->getBackendUser()->doesUserHaveAccess($pidRecord, ($table === 'pages' ? 8 : 16))) { |
||
| 553 | $line['msg'] .= '"' . $line['ref'] . '" cannot be INSERTED on this page! '; |
||
| 554 | } |
||
| 555 | if ($this->pid > 0 && !$this->checkDokType($table, $pidRecord['doktype']) && !$GLOBALS['TCA'][$table]['ctrl']['rootLevel']) { |
||
| 556 | $line['msg'] .= '"' . $table . '" cannot be INSERTED on this page type (change page type to "Folder".) '; |
||
| 557 | } |
||
| 558 | } |
||
| 559 | if (!$this->getBackendUser()->check('tables_modify', $table)) { |
||
| 560 | $line['msg'] .= 'You are not allowed to CREATE "' . $table . '" tables! '; |
||
| 561 | } |
||
| 562 | if ($GLOBALS['TCA'][$table]['ctrl']['readOnly'] ?? false) { |
||
| 563 | $line['msg'] .= 'TABLE "' . $table . '" is READ ONLY! '; |
||
| 564 | } |
||
| 565 | if (($GLOBALS['TCA'][$table]['ctrl']['adminOnly'] ?? false) && !$this->getBackendUser()->isAdmin()) { |
||
| 566 | $line['msg'] .= 'TABLE "' . $table . '" is ADMIN ONLY! '; |
||
| 567 | } |
||
| 568 | if ($GLOBALS['TCA'][$table]['ctrl']['is_static'] ?? false) { |
||
| 569 | $line['msg'] .= 'TABLE "' . $table . '" is a STATIC TABLE! '; |
||
| 570 | } |
||
| 571 | if ((int)($GLOBALS['TCA'][$table]['ctrl']['rootLevel'] ?? 0) === 1) { |
||
| 572 | $line['msg'] .= 'TABLE "' . $table . '" will be inserted on ROOT LEVEL! '; |
||
| 573 | } |
||
| 574 | $databaseRecord = null; |
||
| 575 | if ($this->update) { |
||
| 576 | $databaseRecord = $this->getRecordFromDatabase($table, $uid, $this->showDiff ? '*' : 'uid,pid'); |
||
| 577 | if ($databaseRecord === null) { |
||
| 578 | $line['updatePath'] = '<strong>NEW!</strong>'; |
||
| 579 | } else { |
||
| 580 | $line['updatePath'] = htmlspecialchars($this->getRecordPath((int)($databaseRecord['pid'] ?? 0))); |
||
| 581 | } |
||
| 582 | if ($table === 'sys_file') { |
||
| 583 | $line['updateMode'] = ''; |
||
| 584 | } else { |
||
| 585 | $line['updateMode'] = $this->renderImportModeSelector( |
||
| 586 | $table, |
||
| 587 | $uid, |
||
| 588 | $databaseRecord !== null |
||
| 589 | ); |
||
| 590 | } |
||
| 591 | } |
||
| 592 | // Diff view |
||
| 593 | if ($this->showDiff) { |
||
| 594 | $diffInverse = $this->update ? true : false; |
||
| 595 | // For imports, get new id: |
||
| 596 | if (isset($this->importMapId[$table][$uid]) && $newUid = $this->importMapId[$table][$uid]) { |
||
| 597 | $diffInverse = false; |
||
| 598 | $databaseRecord = $this->getRecordFromDatabase($table, $newUid, '*'); |
||
| 599 | BackendUtility::workspaceOL($table, $databaseRecord); |
||
| 600 | } |
||
| 601 | $importRecord = $this->dat['records'][$table . ':' . $uid]['data'] ?? null; |
||
| 602 | if (is_array($databaseRecord) && is_array($importRecord)) { |
||
| 603 | $line['showDiffContent'] = $this->compareRecords($databaseRecord, $importRecord, $table, $diffInverse); |
||
| 604 | } else { |
||
| 605 | $line['showDiffContent'] = 'ERROR: One of the inputs were not an array!'; |
||
| 606 | } |
||
| 607 | } |
||
| 608 | } |
||
| 609 | } |
||
| 610 | $lines[] = $line; |
||
| 611 | |||
| 612 | // File relations |
||
| 613 | if (is_array($record['filerefs'] ?? null)) { |
||
| 614 | $this->addFiles($record['filerefs'], $lines, $indent); |
||
| 615 | } |
||
| 616 | // Database relations |
||
| 617 | if (is_array($record['rels'] ?? null)) { |
||
| 618 | $this->addRelations($record['rels'], $lines, $indent); |
||
| 619 | } |
||
| 620 | // Soft references |
||
| 621 | if (is_array($record['softrefs'] ?? null)) { |
||
| 622 | $this->addSoftRefs($record['softrefs'], $lines, $indent); |
||
| 623 | } |
||
| 624 | } |
||
| 625 | |||
| 626 | /** |
||
| 627 | * Add database relations of a record to the preview |
||
| 628 | * |
||
| 629 | * @param array $relations Array of relations |
||
| 630 | * @param array $lines Output lines array |
||
| 631 | * @param int $indent Indentation level |
||
| 632 | * @param array $recursionCheck Recursion check stack |
||
| 633 | * |
||
| 634 | * @see addRecord() |
||
| 635 | */ |
||
| 636 | protected function addRelations(array $relations, array &$lines, int $indent, array $recursionCheck = []): void |
||
| 637 | { |
||
| 638 | foreach ($relations as $relation) { |
||
| 639 | $table = $relation['table']; |
||
| 640 | $uid = $relation['id']; |
||
| 641 | $line = []; |
||
| 642 | $line['ref'] = $table . ':' . $uid; |
||
| 643 | $line['type'] = 'rel'; |
||
| 644 | $line['msg'] = ''; |
||
| 645 | if (in_array($line['ref'], $recursionCheck, true)) { |
||
| 646 | continue; |
||
| 647 | } |
||
| 648 | $iconName = 'status-status-checked'; |
||
| 649 | $iconClass = ''; |
||
| 650 | $staticFixed = false; |
||
| 651 | $record = null; |
||
| 652 | if ($uid > 0) { |
||
| 653 | $record = $this->dat['header']['records'][$table][$uid] ?? null; |
||
| 654 | if (!is_array($record)) { |
||
| 655 | if ($this->isTableStatic($table) || $this->isRecordExcluded($table, (int)$uid) |
||
| 656 | || ($relation['tokenID'] ?? '') && !$this->isSoftRefIncluded($relation['tokenID'] ?? '')) { |
||
| 657 | $line['title'] = htmlspecialchars('STATIC: ' . $line['ref']); |
||
| 658 | $iconClass = 'text-info'; |
||
| 659 | $staticFixed = true; |
||
| 660 | } else { |
||
| 661 | $databaseRecord = $this->getRecordFromDatabase($table, (int)$uid); |
||
| 662 | $recordPath = $this->getRecordPath($databaseRecord === null ? 0 : ($table === 'pages' ? (int)$databaseRecord['uid'] : (int)$databaseRecord['pid'])); |
||
| 663 | $line['title'] = sprintf( |
||
| 664 | '<span title="%s">%s</span>', |
||
| 665 | htmlspecialchars($recordPath), |
||
| 666 | htmlspecialchars($line['ref']) |
||
| 667 | ); |
||
| 668 | $line['msg'] = 'LOST RELATION' . ($databaseRecord === null ? ' (Record not found!)' : ' (Path: ' . $recordPath . ')'); |
||
| 669 | $iconClass = 'text-danger'; |
||
| 670 | $iconName = 'status-dialog-warning'; |
||
| 671 | } |
||
| 672 | } else { |
||
| 673 | $recordPath = $this->getRecordPath($table === 'pages' ? (int)$record['uid'] : (int)$record['pid']); |
||
| 674 | $line['title'] = sprintf( |
||
| 675 | '<span title="%s">%s</span>', |
||
| 676 | htmlspecialchars($recordPath), |
||
| 677 | htmlspecialchars((string)$record['title']) |
||
| 678 | ); |
||
| 679 | } |
||
| 680 | } else { |
||
| 681 | // Negative values in relation fields. These are typically fields of sys_language, fe_users etc. |
||
| 682 | // They are static values. They CAN theoretically be negative pointers to uids in other tables, |
||
| 683 | // but this is so rarely used that it is not supported. |
||
| 684 | $line['title'] = htmlspecialchars('FIXED: ' . $line['ref']); |
||
| 685 | $staticFixed = true; |
||
| 686 | } |
||
| 687 | |||
| 688 | $icon = $this->iconFactory->getIcon($iconName, Icon::SIZE_SMALL)->render(); |
||
| 689 | $line['preCode'] = sprintf( |
||
| 690 | '%s<span class="%s" title="%s">%s</span>', |
||
| 691 | $this->renderIndent($indent + 2), |
||
| 692 | $iconClass, |
||
| 693 | htmlspecialchars($line['ref']), |
||
| 694 | $icon |
||
| 695 | ); |
||
| 696 | if (!$staticFixed || $this->showStaticRelations) { |
||
| 697 | $lines[] = $line; |
||
| 698 | if (is_array($record) && is_array($record['rels'] ?? null)) { |
||
| 699 | $this->addRelations($record['rels'], $lines, $indent + 1, array_merge($recursionCheck, [$line['ref']])); |
||
| 700 | } |
||
| 701 | } |
||
| 702 | } |
||
| 703 | } |
||
| 704 | |||
| 705 | /** |
||
| 706 | * Add file relations of a record to the preview. |
||
| 707 | * |
||
| 708 | * Public access for testing purpose only. |
||
| 709 | * |
||
| 710 | * @param array $relations Array of file IDs |
||
| 711 | * @param array $lines Output lines array |
||
| 712 | * @param int $indent Indentation level |
||
| 713 | * @param string $tokenID Token ID if this is a soft reference (in which case it only makes sense with a single element in the $relations array!) |
||
| 714 | * |
||
| 715 | * @see addRecord() |
||
| 716 | */ |
||
| 717 | public function addFiles(array $relations, array &$lines, int $indent, string $tokenID = ''): void |
||
| 718 | { |
||
| 719 | foreach ($relations as $ID) { |
||
| 720 | $line = []; |
||
| 721 | $line['msg'] = ''; |
||
| 722 | $fileInfo = $this->dat['header']['files'][$ID]; |
||
| 723 | if (!is_array($fileInfo)) { |
||
| 724 | if ($tokenID !== '' || $this->isSoftRefIncluded($tokenID)) { |
||
| 725 | $line['msg'] = 'MISSING FILE: ' . $ID; |
||
| 726 | $this->addError('MISSING FILE: ' . $ID); |
||
| 727 | } else { |
||
| 728 | return; |
||
| 729 | } |
||
| 730 | } |
||
| 731 | $line['ref'] = 'FILE'; |
||
| 732 | $line['type'] = 'file'; |
||
| 733 | $line['preCode'] = sprintf( |
||
| 734 | '%s<span title="%s">%s</span>', |
||
| 735 | $this->renderIndent($indent + 2), |
||
| 736 | htmlspecialchars($line['ref']), |
||
| 737 | $this->iconFactory->getIcon('status-reference-hard', Icon::SIZE_SMALL)->render() |
||
| 738 | ); |
||
| 739 | $line['title'] = htmlspecialchars($fileInfo['filename']); |
||
| 740 | $line['showDiffContent'] = PathUtility::stripPathSitePrefix((string)($this->fileIdMap[$ID] ?? '')); |
||
| 741 | // If import mode and there is a non-RTE soft reference, check the destination directory. |
||
| 742 | if ($this->mode === 'import' && $tokenID !== '' && !($fileInfo['RTE_ORIG_ID'] ?? false)) { |
||
| 743 | // Check folder existence |
||
| 744 | if (isset($fileInfo['parentRelFileName'])) { |
||
| 745 | $line['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. '; |
||
| 746 | } else { |
||
| 747 | $origDirPrefix = PathUtility::dirname($fileInfo['relFileName']) . '/'; |
||
| 748 | $dirPrefix = $this->resolveStoragePath($origDirPrefix); |
||
| 749 | if ($dirPrefix === null) { |
||
| 750 | $line['msg'] = 'ERROR: There are no available file mounts to write file in! '; |
||
| 751 | } elseif ($origDirPrefix !== $dirPrefix) { |
||
| 752 | $line['msg'] = 'File will be attempted written to "' . $dirPrefix . '". '; |
||
| 753 | } |
||
| 754 | } |
||
| 755 | // Check file existence |
||
| 756 | if (file_exists(Environment::getPublicPath() . '/' . $fileInfo['relFileName'])) { |
||
| 757 | if ($this->update) { |
||
| 758 | $line['updatePath'] .= 'File exists.'; |
||
| 759 | } else { |
||
| 760 | $line['msg'] .= 'File already exists! '; |
||
| 761 | } |
||
| 762 | } |
||
| 763 | // Check file extension |
||
| 764 | $fileProcObj = $this->getFileProcObj(); |
||
| 765 | if ($fileProcObj->actionPerms['addFile']) { |
||
| 766 | $pathInfo = GeneralUtility::split_fileref(Environment::getPublicPath() . '/' . $fileInfo['relFileName']); |
||
| 767 | if (!GeneralUtility::makeInstance(FileNameValidator::class)->isValid($pathInfo['file'])) { |
||
| 768 | $line['msg'] .= 'File extension was not allowed!'; |
||
| 769 | } |
||
| 770 | } else { |
||
| 771 | $line['msg'] = 'Your user profile does not allow you to create files on the server!'; |
||
| 772 | } |
||
| 773 | } |
||
| 774 | $lines[] = $line; |
||
| 775 | unset($this->remainHeader['files'][$ID]); |
||
| 776 | |||
| 777 | // RTE originals |
||
| 778 | if ($fileInfo['RTE_ORIG_ID'] ?? false) { |
||
| 779 | $ID = $fileInfo['RTE_ORIG_ID']; |
||
| 780 | $line = []; |
||
| 781 | $fileInfo = $this->dat['header']['files'][$ID]; |
||
| 782 | if (!is_array($fileInfo)) { |
||
| 783 | $line['msg'] = 'MISSING RTE original FILE: ' . $ID; |
||
| 784 | $this->addError('MISSING RTE original FILE: ' . $ID); |
||
| 785 | } |
||
| 786 | $line['ref'] = 'FILE'; |
||
| 787 | $line['type'] = 'file'; |
||
| 788 | $line['preCode'] = sprintf( |
||
| 789 | '%s<span title="%s">%s</span>', |
||
| 790 | $this->renderIndent($indent + 4), |
||
| 791 | htmlspecialchars($line['ref']), |
||
| 792 | $this->iconFactory->getIcon('status-reference-hard', Icon::SIZE_SMALL)->render() |
||
| 793 | ); |
||
| 794 | $line['title'] = htmlspecialchars($fileInfo['filename']) . ' <em>(Original)</em>'; |
||
| 795 | $line['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIdMap[$ID]); |
||
| 796 | $lines[] = $line; |
||
| 797 | unset($this->remainHeader['files'][$ID]); |
||
| 798 | } |
||
| 799 | |||
| 800 | // External resources |
||
| 801 | if (is_array($fileInfo['EXT_RES_ID'] ?? null)) { |
||
| 802 | foreach ($fileInfo['EXT_RES_ID'] as $extID) { |
||
| 803 | $line = []; |
||
| 804 | $fileInfo = $this->dat['header']['files'][$extID]; |
||
| 805 | if (!is_array($fileInfo)) { |
||
| 806 | $line['msg'] = 'MISSING External Resource FILE: ' . $extID; |
||
| 807 | $this->addError('MISSING External Resource FILE: ' . $extID); |
||
| 808 | } else { |
||
| 809 | $line['updatePath'] = $fileInfo['parentRelFileName']; |
||
| 810 | } |
||
| 811 | $line['ref'] = 'FILE'; |
||
| 812 | $line['type'] = 'file'; |
||
| 813 | $line['preCode'] = sprintf( |
||
| 814 | '%s<span title="%s">%s</span>', |
||
| 815 | $this->renderIndent($indent + 4), |
||
| 816 | htmlspecialchars($line['ref']), |
||
| 817 | $this->iconFactory->getIcon('actions-insert-reference', Icon::SIZE_SMALL)->render() |
||
| 818 | ); |
||
| 819 | $line['title'] = htmlspecialchars($fileInfo['filename']) . ' <em>(Resource)</em>'; |
||
| 820 | $line['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIdMap[$extID]); |
||
| 821 | $lines[] = $line; |
||
| 822 | unset($this->remainHeader['files'][$extID]); |
||
| 823 | } |
||
| 824 | } |
||
| 825 | } |
||
| 826 | } |
||
| 827 | |||
| 828 | /** |
||
| 829 | * Add soft references of a record to the preview |
||
| 830 | * |
||
| 831 | * @param array $softrefs Soft references |
||
| 832 | * @param array $lines Output lines array |
||
| 833 | * @param int $indent Indentation level |
||
| 834 | * |
||
| 835 | * @see addRecord() |
||
| 836 | */ |
||
| 837 | protected function addSoftRefs(array $softrefs, array &$lines, int $indent): void |
||
| 838 | { |
||
| 839 | foreach ($softrefs as $softref) { |
||
| 840 | $line = []; |
||
| 841 | $line['ref'] = 'SOFTREF'; |
||
| 842 | $line['type'] = 'softref'; |
||
| 843 | $line['msg'] = ''; |
||
| 844 | $line['preCode'] = sprintf( |
||
| 845 | '%s<span title="%s">%s</span>', |
||
| 846 | $this->renderIndent($indent + 2), |
||
| 847 | htmlspecialchars($line['ref']), |
||
| 848 | $this->iconFactory->getIcon('status-reference-soft', Icon::SIZE_SMALL)->render() |
||
| 849 | ); |
||
| 850 | $line['title'] = sprintf( |
||
| 851 | '<em>%s, "%s"</em> : <span title="%s">%s</span>', |
||
| 852 | $softref['field'], |
||
| 853 | $softref['spKey'], |
||
| 854 | htmlspecialchars($softref['matchString']), |
||
| 855 | htmlspecialchars(GeneralUtility::fixed_lgd_cs($softref['matchString'], 60)) |
||
| 856 | ); |
||
| 857 | if ($softref['subst']['type'] ?? false) { |
||
| 858 | if ($softref['subst']['title'] ?? false) { |
||
| 859 | $line['title'] .= sprintf( |
||
| 860 | '<br/>%s<strong>%s</strong> %s', |
||
| 861 | $this->renderIndent($indent + 4), |
||
| 862 | htmlspecialchars($this->lang->getLL('impexpcore_singlereco_title')), |
||
| 863 | htmlspecialchars(GeneralUtility::fixed_lgd_cs($softref['subst']['title'], 60)) |
||
| 864 | ); |
||
| 865 | } |
||
| 866 | if ($softref['subst']['description'] ?? false) { |
||
| 867 | $line['title'] .= sprintf( |
||
| 868 | '<br/>%s<strong>%s</strong> %s', |
||
| 869 | $this->renderIndent($indent + 4), |
||
| 870 | htmlspecialchars($this->lang->getLL('impexpcore_singlereco_descr')), |
||
| 871 | htmlspecialchars(GeneralUtility::fixed_lgd_cs($softref['subst']['description'], 60)) |
||
| 872 | ); |
||
| 873 | } |
||
| 874 | if ($softref['subst']['type'] === 'db') { |
||
| 875 | $line['title'] .= sprintf( |
||
| 876 | '<br/>%s%s <strong>%s</strong>', |
||
| 877 | $this->renderIndent($indent + 4), |
||
| 878 | htmlspecialchars($this->lang->getLL('impexpcore_softrefsel_record')), |
||
| 879 | $softref['subst']['recordRef'] |
||
| 880 | ); |
||
| 881 | } elseif ($softref['subst']['type'] === 'file') { |
||
| 882 | $line['title'] .= sprintf( |
||
| 883 | '<br/>%s%s <strong>%s</strong>', |
||
| 884 | $this->renderIndent($indent + 4), |
||
| 885 | htmlspecialchars($this->lang->getLL('impexpcore_singlereco_filename')), |
||
| 886 | $softref['subst']['relFileName'] |
||
| 887 | ); |
||
| 888 | } elseif ($softref['subst']['type'] === 'string') { |
||
| 889 | $line['title'] .= sprintf( |
||
| 890 | '<br/>%s%s <strong>%s</strong>', |
||
| 891 | $this->renderIndent($indent + 4), |
||
| 892 | htmlspecialchars($this->lang->getLL('impexpcore_singlereco_value')), |
||
| 893 | $softref['subst']['tokenValue'] |
||
| 894 | ); |
||
| 895 | } |
||
| 896 | } |
||
| 897 | $line['_softRefInfo'] = $softref; |
||
| 898 | $mode = $this->softrefCfg[$softref['subst']['tokenID'] ?? null]['mode'] ?? ''; |
||
| 899 | if (isset($softref['error']) && $mode !== Import::SOFTREF_IMPORT_MODE_EDITABLE && $mode !== Import::SOFTREF_IMPORT_MODE_EXCLUDE) { |
||
| 900 | $line['msg'] .= $softref['error']; |
||
| 901 | } |
||
| 902 | $lines[] = $line; |
||
| 903 | |||
| 904 | // Add database relations |
||
| 905 | if (($softref['subst']['type'] ?? '') === 'db') { |
||
| 906 | [$referencedTable, $referencedUid] = explode(':', $softref['subst']['recordRef']); |
||
| 907 | $relations = [['table' => $referencedTable, 'id' => $referencedUid, 'tokenID' => $softref['subst']['tokenID']]]; |
||
| 908 | $this->addRelations($relations, $lines, $indent + 4); |
||
| 909 | } |
||
| 910 | // Add files relations |
||
| 911 | if (($softref['subst']['type'] ?? '') === 'file') { |
||
| 912 | $relations = [$softref['file_ID']]; |
||
| 913 | $this->addFiles($relations, $lines, $indent + 4, $softref['subst']['tokenID']); |
||
| 914 | } |
||
| 915 | } |
||
| 916 | } |
||
| 917 | |||
| 918 | protected function renderIndent(int $indent): string |
||
| 919 | { |
||
| 920 | return str_repeat(' ', $indent); |
||
| 921 | } |
||
| 922 | |||
| 923 | /** |
||
| 924 | * Verifies that a table is allowed on a certain doktype of a page. |
||
| 925 | * |
||
| 926 | * @param string $table Table name to check |
||
| 927 | * @param int $dokType Page doktype |
||
| 928 | * @return bool TRUE if OK |
||
| 929 | */ |
||
| 930 | protected function checkDokType(string $table, int $dokType): bool |
||
| 931 | { |
||
| 932 | $allowedTableList = $GLOBALS['PAGES_TYPES'][$dokType]['allowedTables'] ?? $GLOBALS['PAGES_TYPES']['default']['allowedTables']; |
||
| 933 | $allowedArray = GeneralUtility::trimExplode(',', $allowedTableList, true); |
||
| 934 | if (str_contains($allowedTableList, '*') || in_array($table, $allowedArray, true)) { |
||
| 935 | return true; |
||
| 936 | } |
||
| 937 | return false; |
||
| 938 | } |
||
| 939 | |||
| 940 | /** |
||
| 941 | * Render input controls for import or export |
||
| 942 | * |
||
| 943 | * @param array $line Output line array |
||
| 944 | * @return string HTML |
||
| 945 | */ |
||
| 946 | protected function renderControls(array $line): string |
||
| 947 | { |
||
| 948 | if ($this->mode === 'export') { |
||
| 949 | if ($line['type'] === 'record') { |
||
| 950 | return $this->renderRecordExcludeCheckbox($line['ref']); |
||
| 951 | } |
||
| 952 | if ($line['type'] === 'softref') { |
||
| 953 | return $this->renderSoftRefExportSelector($line['_softRefInfo']); |
||
| 954 | } |
||
| 955 | } elseif ($this->mode === 'import') { |
||
| 956 | if ($line['type'] === 'softref') { |
||
| 957 | return $this->renderSoftRefImportTextField($line['_softRefInfo']); |
||
| 958 | } |
||
| 959 | } |
||
| 960 | return ''; |
||
| 961 | } |
||
| 962 | |||
| 963 | /** |
||
| 964 | * Render check box for exclusion of a record from export. |
||
| 965 | * |
||
| 966 | * @param string $recordRef The record ID of the form [table]:[id]. |
||
| 967 | * @return string HTML |
||
| 968 | */ |
||
| 969 | protected function renderRecordExcludeCheckbox(string $recordRef): string |
||
| 970 | { |
||
| 971 | return sprintf( |
||
| 972 | ' |
||
| 973 | <input type="checkbox" class="t3js-exclude-checkbox" name="tx_impexp[exclude][%1$s]" id="checkExclude%1$s" value="1" /> |
||
| 974 | <label for="checkExclude%1$s">%2$s</label>', |
||
| 975 | $recordRef, |
||
| 976 | htmlspecialchars($this->lang->getLL('impexpcore_singlereco_exclude')) |
||
| 977 | ); |
||
| 978 | } |
||
| 979 | |||
| 980 | /** |
||
| 981 | * Render text field when importing a soft reference. |
||
| 982 | * |
||
| 983 | * @param array $softref Soft reference |
||
| 984 | * @return string HTML |
||
| 985 | */ |
||
| 986 | protected function renderSoftRefImportTextField(array $softref): string |
||
| 987 | { |
||
| 988 | if (isset($softref['subst']['tokenID'])) { |
||
| 989 | $tokenID = $softref['subst']['tokenID']; |
||
| 990 | $cfg = $this->softrefCfg[$tokenID] ?? []; |
||
| 991 | if (($cfg['mode'] ?? '') === Import::SOFTREF_IMPORT_MODE_EDITABLE) { |
||
| 992 | $html = ''; |
||
| 993 | if ($cfg['title'] ?? false) { |
||
| 994 | $html .= '<strong>' . htmlspecialchars((string)$cfg['title']) . '</strong><br/>'; |
||
| 995 | } |
||
| 996 | $html .= htmlspecialchars((string)$cfg['description']) . '<br/>'; |
||
| 997 | $html .= sprintf( |
||
| 998 | '<input type="text" name="tx_impexp[softrefInputValues][%s]" value="%s" />', |
||
| 999 | $tokenID, |
||
| 1000 | htmlspecialchars($this->softrefInputValues[$tokenID] ?? $cfg['defValue']) |
||
| 1001 | ); |
||
| 1002 | return $html; |
||
| 1003 | } |
||
| 1004 | } |
||
| 1005 | |||
| 1006 | return ''; |
||
| 1007 | } |
||
| 1008 | |||
| 1009 | /** |
||
| 1010 | * Render select box with export options for soft references. |
||
| 1011 | * An export box is shown only if a substitution scheme is found for the soft reference. |
||
| 1012 | * |
||
| 1013 | * @param array $softref Soft reference |
||
| 1014 | * @return string HTML |
||
| 1015 | */ |
||
| 1016 | protected function renderSoftRefExportSelector(array $softref): string |
||
| 1017 | { |
||
| 1018 | $fileInfo = isset($softref['file_ID']) ? $this->dat['header']['files'][$softref['file_ID']] : []; |
||
| 1019 | // Substitution scheme has to be around and RTE images MUST be exported. |
||
| 1020 | if (isset($softref['subst']['tokenID']) && !isset($fileInfo['RTE_ORIG_ID'])) { |
||
| 1021 | $options = []; |
||
| 1022 | $options[''] = ''; |
||
| 1023 | $options[Import::SOFTREF_IMPORT_MODE_EDITABLE] = $this->lang->getLL('impexpcore_softrefsel_editable'); |
||
| 1024 | $options[Import::SOFTREF_IMPORT_MODE_EXCLUDE] = $this->lang->getLL('impexpcore_softrefsel_exclude'); |
||
| 1025 | $value = $this->softrefCfg[$softref['subst']['tokenID']]['mode'] ?? ''; |
||
| 1026 | $selectHtml = $this->renderSelectBox( |
||
| 1027 | 'tx_impexp[softrefCfg][' . $softref['subst']['tokenID'] . '][mode]', |
||
| 1028 | $value, |
||
| 1029 | $options |
||
| 1030 | ) . '<br/>'; |
||
| 1031 | $textFieldHtml = ''; |
||
| 1032 | if ($value === Import::SOFTREF_IMPORT_MODE_EDITABLE) { |
||
| 1033 | if ($softref['subst']['title'] ?? false) { |
||
| 1034 | $textFieldHtml .= sprintf( |
||
| 1035 | ' |
||
| 1036 | <input type="hidden" name="tx_impexp[softrefCfg][%1$s][title]" value="%2$s" /> |
||
| 1037 | <strong>%2$s</strong><br/>', |
||
| 1038 | $softref['subst']['tokenID'], |
||
| 1039 | htmlspecialchars($softref['subst']['title']) |
||
| 1040 | ); |
||
| 1041 | } |
||
| 1042 | if (!($softref['subst']['description'] ?? false)) { |
||
| 1043 | $textFieldHtml .= sprintf( |
||
| 1044 | ' |
||
| 1045 | %s<br/> |
||
| 1046 | <input type="text" name="tx_impexp[softrefCfg][%s][description]" value="%s" />', |
||
| 1047 | htmlspecialchars($this->lang->getLL('impexpcore_printerror_description')), |
||
| 1048 | $softref['subst']['tokenID'], |
||
| 1049 | htmlspecialchars($this->softrefCfg[$softref['subst']['tokenID']]['description'] ?? '') |
||
| 1050 | ); |
||
| 1051 | } else { |
||
| 1052 | $textFieldHtml .= sprintf( |
||
| 1053 | ' |
||
| 1054 | <input type="hidden" name="tx_impexp[softrefCfg][%1$s][description]" value="%2$s" />%2$s', |
||
| 1055 | $softref['subst']['tokenID'], |
||
| 1056 | htmlspecialchars($softref['subst']['description']) |
||
| 1057 | ); |
||
| 1058 | } |
||
| 1059 | $textFieldHtml .= sprintf( |
||
| 1060 | ' |
||
| 1061 | <input type="hidden" name="tx_impexp[softrefCfg][%s][defValue]" value="%s" />', |
||
| 1062 | $softref['subst']['tokenID'], |
||
| 1063 | htmlspecialchars($softref['subst']['tokenValue']) |
||
| 1064 | ); |
||
| 1065 | } |
||
| 1066 | return $selectHtml . $textFieldHtml; |
||
| 1067 | } |
||
| 1068 | return ''; |
||
| 1069 | } |
||
| 1070 | |||
| 1071 | /** |
||
| 1072 | * Render select box with import options for the record. |
||
| 1073 | * |
||
| 1074 | * @param string $table Table name |
||
| 1075 | * @param int $uid Record UID |
||
| 1076 | * @param bool $doesRecordExist Is there already a record with this UID in the database? |
||
| 1077 | * @return string HTML |
||
| 1078 | */ |
||
| 1079 | protected function renderImportModeSelector(string $table, int $uid, bool $doesRecordExist): string |
||
| 1080 | { |
||
| 1081 | $options = []; |
||
| 1082 | if (!$doesRecordExist) { |
||
| 1083 | $options[] = $this->lang->getLL('impexpcore_singlereco_insert'); |
||
| 1084 | if ($this->getBackendUser()->isAdmin()) { |
||
| 1085 | $options[Import::IMPORT_MODE_FORCE_UID] = sprintf($this->lang->getLL('impexpcore_singlereco_forceUidSAdmin'), $uid); |
||
| 1086 | } |
||
| 1087 | } else { |
||
| 1088 | $options[] = $this->lang->getLL('impexpcore_singlereco_update'); |
||
| 1089 | $options[Import::IMPORT_MODE_AS_NEW] = $this->lang->getLL('impexpcore_singlereco_importAsNew'); |
||
| 1090 | if (!$this->globalIgnorePid) { |
||
| 1091 | $options[Import::IMPORT_MODE_IGNORE_PID] = $this->lang->getLL('impexpcore_singlereco_ignorePid'); |
||
| 1092 | } else { |
||
| 1093 | $options[Import::IMPORT_MODE_RESPECT_PID] = $this->lang->getLL('impexpcore_singlereco_respectPid'); |
||
| 1094 | } |
||
| 1095 | } |
||
| 1096 | $options[Import::IMPORT_MODE_EXCLUDE] = $this->lang->getLL('impexpcore_singlereco_exclude'); |
||
| 1097 | return $this->renderSelectBox( |
||
| 1098 | 'tx_impexp[import_mode][' . $table . ':' . $uid . ']', |
||
| 1099 | (string)($this->importMode[$table . ':' . $uid] ?? ''), |
||
| 1100 | $options |
||
| 1101 | ); |
||
| 1102 | } |
||
| 1103 | |||
| 1104 | /** |
||
| 1105 | * Renders a select box from option values. |
||
| 1106 | * |
||
| 1107 | * @param string $name Form element name |
||
| 1108 | * @param string $value Current value |
||
| 1109 | * @param array $options Options to display (key/value pairs) |
||
| 1110 | * @return string HTML |
||
| 1111 | */ |
||
| 1112 | protected function renderSelectBox(string $name, string $value, array $options): string |
||
| 1113 | { |
||
| 1114 | $optionsHtml = ''; |
||
| 1115 | $isValueInOptions = false; |
||
| 1116 | |||
| 1117 | foreach ($options as $k => $v) { |
||
| 1118 | if ((string)$k === $value) { |
||
| 1119 | $isValueInOptions = true; |
||
| 1120 | $selectedHtml = ' selected="selected"'; |
||
| 1121 | } else { |
||
| 1122 | $selectedHtml = ''; |
||
| 1123 | } |
||
| 1124 | $optionsHtml .= sprintf( |
||
| 1125 | '<option value="%s"%s>%s</option>', |
||
| 1126 | htmlspecialchars((string)$k), |
||
| 1127 | $selectedHtml, |
||
| 1128 | htmlspecialchars((string)$v) |
||
| 1129 | ); |
||
| 1130 | } |
||
| 1131 | |||
| 1132 | // Append and select the current value as an option of the form "[value]" |
||
| 1133 | // if it is not available in the options. |
||
| 1134 | if (!$isValueInOptions && $value !== '') { |
||
| 1135 | $optionsHtml .= sprintf( |
||
| 1136 | '<option value="%s" selected="selected">%s</option>', |
||
| 1137 | htmlspecialchars($value), |
||
| 1138 | htmlspecialchars('[\'' . $value . '\']') |
||
| 1139 | ); |
||
| 1140 | } |
||
| 1141 | |||
| 1142 | return '<select name="' . $name . '">' . $optionsHtml . '</select>'; |
||
| 1143 | } |
||
| 1144 | |||
| 1145 | /***************************** |
||
| 1146 | * Helper functions of kinds |
||
| 1147 | *****************************/ |
||
| 1148 | |||
| 1149 | /** |
||
| 1150 | * @return string |
||
| 1151 | */ |
||
| 1152 | public function getFileadminFolderName(): string |
||
| 1153 | { |
||
| 1154 | if (empty($this->fileadminFolderName)) { |
||
| 1155 | if (!empty($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'])) { |
||
| 1156 | $this->fileadminFolderName = rtrim($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/'); |
||
| 1157 | } else { |
||
| 1158 | $this->fileadminFolderName = 'fileadmin'; |
||
| 1159 | } |
||
| 1160 | } |
||
| 1161 | return $this->fileadminFolderName; |
||
| 1162 | } |
||
| 1163 | |||
| 1164 | /** |
||
| 1165 | * @return string |
||
| 1166 | */ |
||
| 1167 | public function getOrCreateTemporaryFolderName(): string |
||
| 1168 | { |
||
| 1169 | if (empty($this->temporaryFolderName)) { |
||
| 1170 | $this->temporaryFolderName = $this->createTemporaryFolderName(); |
||
| 1171 | } |
||
| 1172 | return $this->temporaryFolderName; |
||
| 1173 | } |
||
| 1174 | |||
| 1175 | protected function createTemporaryFolderName(): string |
||
| 1176 | { |
||
| 1177 | $temporaryPath = Environment::getVarPath() . '/transient'; |
||
| 1178 | do { |
||
| 1179 | $temporaryFolderName = sprintf( |
||
| 1180 | '%s/impexp_%s_files_%d', |
||
| 1181 | $temporaryPath, |
||
| 1182 | $this->mode, |
||
| 1183 | random_int(1, PHP_INT_MAX) |
||
| 1184 | ); |
||
| 1185 | } while (is_dir($temporaryFolderName)); |
||
| 1186 | GeneralUtility::mkdir_deep($temporaryFolderName); |
||
| 1187 | return $temporaryFolderName; |
||
| 1188 | } |
||
| 1189 | |||
| 1190 | public function removeTemporaryFolderName(): void |
||
| 1191 | { |
||
| 1192 | if (!empty($this->temporaryFolderName)) { |
||
| 1193 | GeneralUtility::rmdir($this->temporaryFolderName, true); |
||
| 1194 | $this->temporaryFolderName = null; |
||
| 1195 | } |
||
| 1196 | } |
||
| 1197 | |||
| 1198 | /** |
||
| 1199 | * Returns a \TYPO3\CMS\Core\Resource\Folder object for saving export files |
||
| 1200 | * to the server and is also used for uploading import files. |
||
| 1201 | * |
||
| 1202 | * @return Folder|null |
||
| 1203 | */ |
||
| 1204 | public function getOrCreateDefaultImportExportFolder(): ?Folder |
||
| 1205 | { |
||
| 1206 | if (empty($this->defaultImportExportFolder)) { |
||
| 1207 | $this->createDefaultImportExportFolder(); |
||
| 1208 | } |
||
| 1209 | return $this->defaultImportExportFolder; |
||
| 1210 | } |
||
| 1211 | |||
| 1212 | /** |
||
| 1213 | * Creates a \TYPO3\CMS\Core\Resource\Folder object for saving export files |
||
| 1214 | * to the server and is also used for uploading import files. |
||
| 1215 | */ |
||
| 1216 | protected function createDefaultImportExportFolder(): void |
||
| 1217 | { |
||
| 1218 | $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder(); |
||
| 1219 | $defaultImportExportFolder = null; |
||
| 1220 | $importExportFolderName = 'importexport'; |
||
| 1221 | |||
| 1222 | if ($defaultTemporaryFolder !== null) { |
||
| 1223 | if ($defaultTemporaryFolder->hasFolder($importExportFolderName) === false) { |
||
| 1224 | $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName); |
||
| 1225 | } else { |
||
| 1226 | $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName); |
||
| 1227 | } |
||
| 1228 | } |
||
| 1229 | $this->defaultImportExportFolder = $defaultImportExportFolder; |
||
| 1230 | } |
||
| 1231 | |||
| 1232 | public function removeDefaultImportExportFolder(): void |
||
| 1233 | { |
||
| 1234 | if (!empty($this->defaultImportExportFolder)) { |
||
| 1235 | $this->defaultImportExportFolder->delete(true); |
||
| 1236 | $this->defaultImportExportFolder = null; |
||
| 1237 | } |
||
| 1238 | } |
||
| 1239 | |||
| 1240 | /** |
||
| 1241 | * Checks if the input path relative to the public web path can be found in the file mounts of the backend user. |
||
| 1242 | * If not, it checks all file mounts of the user for the relative path and returns it if found. |
||
| 1243 | * |
||
| 1244 | * @param string $dirPrefix Path relative to public web path. |
||
| 1245 | * @param bool $checkAlternatives If set to false, do not look for an alternative path. |
||
| 1246 | * @return string If a path is available, it will be returned, otherwise NULL. |
||
| 1247 | * @throws \Exception |
||
| 1248 | */ |
||
| 1249 | protected function resolveStoragePath(string $dirPrefix, bool $checkAlternatives = true): ?string |
||
| 1250 | { |
||
| 1251 | try { |
||
| 1252 | GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier($dirPrefix); |
||
| 1253 | return $dirPrefix; |
||
| 1254 | } catch (InsufficientFolderAccessPermissionsException $e) { |
||
| 1255 | if ($checkAlternatives) { |
||
| 1256 | $storagesByUser = $this->getBackendUser()->getFileStorages(); |
||
| 1257 | foreach ($storagesByUser as $storage) { |
||
| 1258 | try { |
||
| 1259 | $folder = $storage->getFolder(rtrim($dirPrefix, '/')); |
||
| 1260 | return $folder->getPublicUrl(); |
||
| 1261 | } catch (InsufficientFolderAccessPermissionsException $e) { |
||
|
|
|||
| 1262 | } |
||
| 1263 | } |
||
| 1264 | } |
||
| 1265 | } |
||
| 1266 | return null; |
||
| 1267 | } |
||
| 1268 | |||
| 1269 | /** |
||
| 1270 | * Recursively flattening the $pageTree array to a one-dimensional array with uid-pid pairs. |
||
| 1271 | * |
||
| 1272 | * @param array $pageTree Page tree array |
||
| 1273 | * @param array $list List with uid-pid pairs |
||
| 1274 | * @param int $pid PID value (internal, don't set from outside) |
||
| 1275 | */ |
||
| 1276 | protected function flatInversePageTree(array $pageTree, array &$list, int $pid = -1): void |
||
| 1277 | { |
||
| 1278 | // @todo: return $list instead of by-reference?! |
||
| 1279 | $pageTreeInverse = array_reverse($pageTree); |
||
| 1280 | foreach ($pageTreeInverse as $page) { |
||
| 1281 | $list[$page['uid']] = $pid; |
||
| 1282 | if (is_array($page['subrow'] ?? null)) { |
||
| 1283 | $this->flatInversePageTree($page['subrow'], $list, (int)$page['uid']); |
||
| 1284 | } |
||
| 1285 | } |
||
| 1286 | } |
||
| 1287 | |||
| 1288 | /** |
||
| 1289 | * Returns TRUE if the input table name is to be regarded as a static relation (that is, not exported etc). |
||
| 1290 | * |
||
| 1291 | * @param string $table Table name |
||
| 1292 | * @return bool TRUE, if table is marked static |
||
| 1293 | */ |
||
| 1294 | protected function isTableStatic(string $table): bool |
||
| 1295 | { |
||
| 1296 | if (is_array($GLOBALS['TCA'][$table] ?? null)) { |
||
| 1297 | return ($GLOBALS['TCA'][$table]['ctrl']['is_static'] ?? false) |
||
| 1298 | || in_array($table, $this->relStaticTables, true) |
||
| 1299 | || in_array('_ALL', $this->relStaticTables, true); |
||
| 1300 | } |
||
| 1301 | return false; |
||
| 1302 | } |
||
| 1303 | |||
| 1304 | /** |
||
| 1305 | * Returns TRUE if the element should be excluded from import and export. |
||
| 1306 | * |
||
| 1307 | * @param string $table Table name |
||
| 1308 | * @param int $uid Record UID |
||
| 1309 | * @return bool TRUE, if the record should be excluded |
||
| 1310 | */ |
||
| 1311 | protected function isRecordExcluded(string $table, int $uid): bool |
||
| 1312 | { |
||
| 1313 | return (bool)($this->excludeMap[$table . ':' . $uid] ?? false); |
||
| 1314 | } |
||
| 1315 | |||
| 1316 | /** |
||
| 1317 | * Returns TRUE if the soft reference should be included in export. |
||
| 1318 | * |
||
| 1319 | * @param string $tokenID Token ID for soft reference |
||
| 1320 | * @return bool TRUE, if soft reference should be included |
||
| 1321 | */ |
||
| 1322 | protected function isSoftRefIncluded(string $tokenID): bool |
||
| 1323 | { |
||
| 1324 | $mode = $this->softrefCfg[$tokenID]['mode'] ?? ''; |
||
| 1325 | return $tokenID && $mode !== Import::SOFTREF_IMPORT_MODE_EXCLUDE && $mode !== Import::SOFTREF_IMPORT_MODE_EDITABLE; |
||
| 1326 | } |
||
| 1327 | |||
| 1328 | /** |
||
| 1329 | * Returns given fields of record if it exists. |
||
| 1330 | * |
||
| 1331 | * @param string $table Table name |
||
| 1332 | * @param int $uid UID of record |
||
| 1333 | * @param string $fields Field list to select. Default is "uid,pid" |
||
| 1334 | * @return array|null Result of \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord() which means the record if found, otherwise NULL |
||
| 1335 | */ |
||
| 1336 | protected function getRecordFromDatabase(string $table, int $uid, string $fields = 'uid,pid'): ?array |
||
| 1337 | { |
||
| 1338 | return BackendUtility::getRecord($table, $uid, $fields); |
||
| 1339 | } |
||
| 1340 | |||
| 1341 | /** |
||
| 1342 | * Returns the page title path of a PID value. Results are cached internally |
||
| 1343 | * |
||
| 1344 | * @param int $pid Record PID to check |
||
| 1345 | * @return string The path for the input PID |
||
| 1346 | */ |
||
| 1347 | protected function getRecordPath(int $pid): string |
||
| 1348 | { |
||
| 1349 | if (!isset($this->cacheGetRecordPath[$pid])) { |
||
| 1350 | $this->cacheGetRecordPath[$pid] = (string)BackendUtility::getRecordPath($pid, $this->permsClause, 20); |
||
| 1351 | } |
||
| 1352 | return $this->cacheGetRecordPath[$pid]; |
||
| 1353 | } |
||
| 1354 | |||
| 1355 | /** |
||
| 1356 | * Compares two records, the current database record and the one from the import memory. |
||
| 1357 | * Will return HTML code to show any differences between them! |
||
| 1358 | * |
||
| 1359 | * @param array $databaseRecord Database record, all fields (old values) |
||
| 1360 | * @param array $importRecord Import memory record for the same table/uid, all fields (new values) |
||
| 1361 | * @param string $table The table name of the record |
||
| 1362 | * @param bool $inverse Inverse the diff view (switch red/green, needed for pre-update difference view) |
||
| 1363 | * @return string HTML |
||
| 1364 | */ |
||
| 1365 | protected function compareRecords(array $databaseRecord, array $importRecord, string $table, bool $inverse = false): string |
||
| 1366 | { |
||
| 1367 | $diffHtml = ''; |
||
| 1368 | |||
| 1369 | // Updated fields |
||
| 1370 | foreach ($databaseRecord as $fieldName => $_) { |
||
| 1371 | if (is_array($GLOBALS['TCA'][$table]['columns'][$fieldName] ?? null) |
||
| 1372 | && $GLOBALS['TCA'][$table]['columns'][$fieldName]['config']['type'] !== 'passthrough' |
||
| 1373 | ) { |
||
| 1374 | if (isset($importRecord[$fieldName])) { |
||
| 1375 | if (trim((string)$databaseRecord[$fieldName]) !== trim((string)$importRecord[$fieldName])) { |
||
| 1376 | $diffFieldHtml = $this->getDiffUtility()->makeDiffDisplay( |
||
| 1377 | BackendUtility::getProcessedValue( |
||
| 1378 | $table, |
||
| 1379 | $fieldName, |
||
| 1380 | !$inverse ? $importRecord[$fieldName] : $databaseRecord[$fieldName], |
||
| 1381 | 0, |
||
| 1382 | true, |
||
| 1383 | true |
||
| 1384 | ), |
||
| 1385 | BackendUtility::getProcessedValue( |
||
| 1386 | $table, |
||
| 1387 | $fieldName, |
||
| 1388 | !$inverse ? $databaseRecord[$fieldName] : $importRecord[$fieldName], |
||
| 1389 | 0, |
||
| 1390 | true, |
||
| 1391 | true |
||
| 1392 | ) |
||
| 1393 | ); |
||
| 1394 | $diffHtml .= sprintf( |
||
| 1395 | '<tr><td>%s (%s)</td><td>%s</td></tr>' . PHP_EOL, |
||
| 1396 | htmlspecialchars($this->lang->sL($GLOBALS['TCA'][$table]['columns'][$fieldName]['label'])), |
||
| 1397 | htmlspecialchars((string)$fieldName), |
||
| 1398 | $diffFieldHtml |
||
| 1399 | ); |
||
| 1400 | } |
||
| 1401 | unset($importRecord[$fieldName]); |
||
| 1402 | } |
||
| 1403 | } |
||
| 1404 | } |
||
| 1405 | |||
| 1406 | // New fields |
||
| 1407 | foreach ($importRecord as $fieldName => $_) { |
||
| 1408 | if (is_array($GLOBALS['TCA'][$table]['columns'][$fieldName] ?? null) |
||
| 1409 | && $GLOBALS['TCA'][$table]['columns'][$fieldName]['config']['type'] !== 'passthrough' |
||
| 1410 | ) { |
||
| 1411 | $diffFieldHtml = '<strong>Field missing</strong> in database'; |
||
| 1412 | $diffHtml .= sprintf( |
||
| 1413 | '<tr><td>%s (%s)</td><td>%s</td></tr>' . PHP_EOL, |
||
| 1414 | htmlspecialchars($this->lang->sL($GLOBALS['TCA'][$table]['columns'][$fieldName]['label'])), |
||
| 1415 | htmlspecialchars((string)$fieldName), |
||
| 1416 | $diffFieldHtml |
||
| 1417 | ); |
||
| 1418 | } |
||
| 1419 | } |
||
| 1420 | |||
| 1421 | if ($diffHtml !== '') { |
||
| 1422 | $diffHtml = '<table class="table table-striped table-hover">' . PHP_EOL . $diffHtml . '</table>'; |
||
| 1423 | } else { |
||
| 1424 | $diffHtml = 'Match'; |
||
| 1425 | } |
||
| 1426 | |||
| 1427 | return sprintf( |
||
| 1428 | '<strong class="text-nowrap">[%s]:</strong>' . PHP_EOL . '%s', |
||
| 1429 | htmlspecialchars($table . ':' . $importRecord['uid'] . ' => ' . $databaseRecord['uid']), |
||
| 1430 | $diffHtml |
||
| 1431 | ); |
||
| 1432 | } |
||
| 1433 | |||
| 1434 | /** |
||
| 1435 | * Returns string comparing object, initialized only once. |
||
| 1436 | * |
||
| 1437 | * @return DiffUtility String comparing object |
||
| 1438 | */ |
||
| 1439 | protected function getDiffUtility(): DiffUtility |
||
| 1440 | { |
||
| 1441 | if ($this->diffUtility === null) { |
||
| 1442 | $this->diffUtility = GeneralUtility::makeInstance(DiffUtility::class); |
||
| 1443 | } |
||
| 1444 | return $this->diffUtility; |
||
| 1445 | } |
||
| 1446 | |||
| 1447 | /** |
||
| 1448 | * Returns file processing object, initialized only once. |
||
| 1449 | * |
||
| 1450 | * @return ExtendedFileUtility File processor object |
||
| 1451 | */ |
||
| 1452 | protected function getFileProcObj(): ExtendedFileUtility |
||
| 1453 | { |
||
| 1454 | if ($this->fileProcObj === null) { |
||
| 1455 | $this->fileProcObj = GeneralUtility::makeInstance(ExtendedFileUtility::class); |
||
| 1456 | $this->fileProcObj->setActionPermissions(); |
||
| 1457 | } |
||
| 1458 | return $this->fileProcObj; |
||
| 1459 | } |
||
| 1460 | |||
| 1461 | /** |
||
| 1462 | * Returns storage repository object, initialized only once. |
||
| 1463 | * |
||
| 1464 | * @return StorageRepository Storage repository object |
||
| 1465 | */ |
||
| 1466 | protected function getStorageRepository(): StorageRepository |
||
| 1467 | { |
||
| 1468 | if ($this->storageRepository === null) { |
||
| 1469 | $this->storageRepository = GeneralUtility::makeInstance(StorageRepository::class); |
||
| 1470 | } |
||
| 1471 | return $this->storageRepository; |
||
| 1472 | } |
||
| 1473 | |||
| 1474 | /***************************** |
||
| 1475 | * Error handling |
||
| 1476 | *****************************/ |
||
| 1477 | |||
| 1478 | /** |
||
| 1479 | * Sets error message in the internal error log |
||
| 1480 | * |
||
| 1481 | * @param string $message Error message |
||
| 1482 | */ |
||
| 1483 | protected function addError(string $message): void |
||
| 1484 | { |
||
| 1485 | $this->errorLog[] = $message; |
||
| 1486 | } |
||
| 1487 | |||
| 1488 | public function hasErrors(): bool |
||
| 1489 | { |
||
| 1490 | return empty($this->errorLog) === false; |
||
| 1491 | } |
||
| 1492 | |||
| 1493 | /** |
||
| 1494 | * @return BackendUserAuthentication |
||
| 1495 | */ |
||
| 1496 | protected function getBackendUser(): BackendUserAuthentication |
||
| 1497 | { |
||
| 1498 | return $GLOBALS['BE_USER']; |
||
| 1499 | } |
||
| 1500 | |||
| 1501 | /** |
||
| 1502 | * @return LanguageService |
||
| 1503 | */ |
||
| 1504 | protected function getLanguageService(): LanguageService |
||
| 1505 | { |
||
| 1506 | return $GLOBALS['LANG']; |
||
| 1507 | } |
||
| 1508 | |||
| 1509 | /************************** |
||
| 1510 | * Getters and Setters |
||
| 1511 | *************************/ |
||
| 1512 | |||
| 1513 | /** |
||
| 1514 | * @return int |
||
| 1515 | */ |
||
| 1516 | public function getPid(): int |
||
| 1517 | { |
||
| 1518 | return $this->pid; |
||
| 1519 | } |
||
| 1520 | |||
| 1521 | /** |
||
| 1522 | * @param int $pid |
||
| 1523 | */ |
||
| 1524 | public function setPid(int $pid): void |
||
| 1525 | { |
||
| 1526 | $this->pid = $pid; |
||
| 1527 | $this->pidRecord = null; |
||
| 1528 | } |
||
| 1529 | |||
| 1530 | /** |
||
| 1531 | * Return record of root page of import or of export page tree |
||
| 1532 | * - or null if access denied to that page. |
||
| 1533 | * |
||
| 1534 | * If the page is the root of the page tree, |
||
| 1535 | * add some basic but missing information. |
||
| 1536 | * |
||
| 1537 | * @return array|null |
||
| 1538 | */ |
||
| 1539 | protected function getPidRecord(): ?array |
||
| 1540 | { |
||
| 1541 | if ($this->pidRecord === null && $this->pid >= 0) { |
||
| 1542 | $pidRecord = BackendUtility::readPageAccess($this->pid, $this->permsClause); |
||
| 1543 | |||
| 1544 | if (is_array($pidRecord)) { |
||
| 1545 | if ($this->pid === 0) { |
||
| 1546 | $pidRecord += ['title' => '[root-level]', 'uid' => 0, 'pid' => 0]; |
||
| 1547 | } |
||
| 1548 | $this->pidRecord = $pidRecord; |
||
| 1549 | } |
||
| 1550 | } |
||
| 1551 | |||
| 1552 | return $this->pidRecord; |
||
| 1553 | } |
||
| 1554 | |||
| 1555 | /** |
||
| 1556 | * Set flag to control whether disabled records and their children are excluded (true) or included (false). Defaults |
||
| 1557 | * to the old behaviour of including everything. |
||
| 1558 | * |
||
| 1559 | * @param bool $excludeDisabledRecords Set to true if if all disabled records should be excluded, false otherwise |
||
| 1560 | */ |
||
| 1561 | public function setExcludeDisabledRecords(bool $excludeDisabledRecords): void |
||
| 1562 | { |
||
| 1563 | $this->excludeDisabledRecords = $excludeDisabledRecords; |
||
| 1564 | } |
||
| 1565 | |||
| 1566 | /** |
||
| 1567 | * @return bool |
||
| 1568 | */ |
||
| 1569 | public function isExcludeDisabledRecords(): bool |
||
| 1570 | { |
||
| 1571 | return $this->excludeDisabledRecords; |
||
| 1572 | } |
||
| 1573 | |||
| 1574 | /** |
||
| 1575 | * @return array |
||
| 1576 | */ |
||
| 1577 | public function getExcludeMap(): array |
||
| 1578 | { |
||
| 1579 | return $this->excludeMap; |
||
| 1580 | } |
||
| 1581 | |||
| 1582 | /** |
||
| 1583 | * @param array $excludeMap |
||
| 1584 | */ |
||
| 1585 | public function setExcludeMap(array $excludeMap): void |
||
| 1588 | } |
||
| 1589 | |||
| 1590 | /** |
||
| 1591 | * @return array |
||
| 1592 | */ |
||
| 1593 | public function getSoftrefCfg(): array |
||
| 1594 | { |
||
| 1595 | return $this->softrefCfg; |
||
| 1596 | } |
||
| 1597 | |||
| 1598 | /** |
||
| 1599 | * @param array $softrefCfg |
||
| 1600 | */ |
||
| 1601 | public function setSoftrefCfg(array $softrefCfg): void |
||
| 1602 | { |
||
| 1603 | $this->softrefCfg = $softrefCfg; |
||
| 1604 | } |
||
| 1605 | |||
| 1606 | /** |
||
| 1607 | * @return array |
||
| 1608 | */ |
||
| 1609 | public function getExtensionDependencies(): array |
||
| 1610 | { |
||
| 1611 | return $this->extensionDependencies; |
||
| 1612 | } |
||
| 1613 | |||
| 1614 | /** |
||
| 1615 | * @param array $extensionDependencies |
||
| 1616 | */ |
||
| 1617 | public function setExtensionDependencies(array $extensionDependencies): void |
||
| 1618 | { |
||
| 1619 | $this->extensionDependencies = $extensionDependencies; |
||
| 1620 | } |
||
| 1621 | |||
| 1622 | /** |
||
| 1623 | * @return bool |
||
| 1624 | */ |
||
| 1625 | public function isShowStaticRelations(): bool |
||
| 1626 | { |
||
| 1627 | return $this->showStaticRelations; |
||
| 1628 | } |
||
| 1629 | |||
| 1630 | /** |
||
| 1631 | * @param bool $showStaticRelations |
||
| 1632 | */ |
||
| 1633 | public function setShowStaticRelations(bool $showStaticRelations): void |
||
| 1634 | { |
||
| 1635 | $this->showStaticRelations = $showStaticRelations; |
||
| 1636 | } |
||
| 1637 | |||
| 1638 | /** |
||
| 1639 | * @return array |
||
| 1640 | */ |
||
| 1641 | public function getRelStaticTables(): array |
||
| 1642 | { |
||
| 1643 | return $this->relStaticTables; |
||
| 1644 | } |
||
| 1645 | |||
| 1646 | /** |
||
| 1647 | * @param array $relStaticTables |
||
| 1648 | */ |
||
| 1649 | public function setRelStaticTables(array $relStaticTables): void |
||
| 1650 | { |
||
| 1651 | $this->relStaticTables = $relStaticTables; |
||
| 1652 | } |
||
| 1653 | |||
| 1654 | /** |
||
| 1655 | * @return array |
||
| 1656 | */ |
||
| 1657 | public function getErrorLog(): array |
||
| 1660 | } |
||
| 1661 | |||
| 1662 | /** |
||
| 1663 | * @param array $errorLog |
||
| 1664 | */ |
||
| 1665 | public function setErrorLog(array $errorLog): void |
||
| 1666 | { |
||
| 1667 | $this->errorLog = $errorLog; |
||
| 1668 | } |
||
| 1669 | |||
| 1670 | /** |
||
| 1671 | * @return bool |
||
| 1672 | */ |
||
| 1673 | public function isUpdate(): bool |
||
| 1674 | { |
||
| 1675 | return $this->update; |
||
| 1676 | } |
||
| 1677 | |||
| 1678 | /** |
||
| 1679 | * @param bool $update |
||
| 1680 | */ |
||
| 1681 | public function setUpdate(bool $update): void |
||
| 1682 | { |
||
| 1683 | $this->update = $update; |
||
| 1684 | } |
||
| 1685 | |||
| 1686 | /** |
||
| 1687 | * @return array |
||
| 1688 | */ |
||
| 1689 | public function getImportMode(): array |
||
| 1690 | { |
||
| 1691 | return $this->importMode; |
||
| 1692 | } |
||
| 1693 | |||
| 1694 | /** |
||
| 1695 | * @param array $importMode |
||
| 1696 | */ |
||
| 1697 | public function setImportMode(array $importMode): void |
||
| 1698 | { |
||
| 1699 | $this->importMode = $importMode; |
||
| 1700 | } |
||
| 1701 | |||
| 1702 | /** |
||
| 1703 | * @return bool |
||
| 1704 | */ |
||
| 1705 | public function isGlobalIgnorePid(): bool |
||
| 1706 | { |
||
| 1707 | return $this->globalIgnorePid; |
||
| 1708 | } |
||
| 1709 | |||
| 1710 | /** |
||
| 1711 | * @param bool $globalIgnorePid |
||
| 1712 | */ |
||
| 1713 | public function setGlobalIgnorePid(bool $globalIgnorePid): void |
||
| 1714 | { |
||
| 1715 | $this->globalIgnorePid = $globalIgnorePid; |
||
| 1716 | } |
||
| 1717 | |||
| 1718 | /** |
||
| 1719 | * @return bool |
||
| 1720 | */ |
||
| 1721 | public function isForceAllUids(): bool |
||
| 1722 | { |
||
| 1723 | return $this->forceAllUids; |
||
| 1724 | } |
||
| 1725 | |||
| 1726 | /** |
||
| 1727 | * @param bool $forceAllUids |
||
| 1728 | */ |
||
| 1729 | public function setForceAllUids(bool $forceAllUids): void |
||
| 1730 | { |
||
| 1731 | $this->forceAllUids = $forceAllUids; |
||
| 1732 | } |
||
| 1733 | |||
| 1734 | /** |
||
| 1735 | * @return bool |
||
| 1736 | */ |
||
| 1737 | public function isShowDiff(): bool |
||
| 1738 | { |
||
| 1739 | return $this->showDiff; |
||
| 1740 | } |
||
| 1741 | |||
| 1742 | /** |
||
| 1743 | * @param bool $showDiff |
||
| 1744 | */ |
||
| 1745 | public function setShowDiff(bool $showDiff): void |
||
| 1748 | } |
||
| 1749 | |||
| 1750 | /** |
||
| 1751 | * @return array |
||
| 1752 | */ |
||
| 1753 | public function getSoftrefInputValues(): array |
||
| 1754 | { |
||
| 1755 | return $this->softrefInputValues; |
||
| 1756 | } |
||
| 1757 | |||
| 1758 | /** |
||
| 1759 | * @param array $softrefInputValues |
||
| 1760 | */ |
||
| 1761 | public function setSoftrefInputValues(array $softrefInputValues): void |
||
| 1762 | { |
||
| 1763 | $this->softrefInputValues = $softrefInputValues; |
||
| 1764 | } |
||
| 1765 | |||
| 1766 | /** |
||
| 1767 | * @return string |
||
| 1768 | */ |
||
| 1769 | public function getMode(): string |
||
| 1772 | } |
||
| 1773 | |||
| 1774 | /** |
||
| 1775 | * @param string $mode |
||
| 1776 | */ |
||
| 1777 | public function setMode(string $mode): void |
||
| 1778 | { |
||
| 1779 | $this->mode = $mode; |
||
| 1780 | } |
||
| 1781 | |||
| 1782 | /** |
||
| 1783 | * @return array |
||
| 1784 | */ |
||
| 1785 | public function getImportMapId(): array |
||
| 1786 | { |
||
| 1787 | return $this->importMapId; |
||
| 1788 | } |
||
| 1789 | |||
| 1790 | /** |
||
| 1791 | * @param array $importMapId |
||
| 1792 | */ |
||
| 1793 | public function setImportMapId(array $importMapId): void |
||
| 1794 | { |
||
| 1795 | $this->importMapId = $importMapId; |
||
| 1796 | } |
||
| 1797 | |||
| 1798 | /** |
||
| 1799 | * @return array |
||
| 1800 | */ |
||
| 1801 | public function getDat(): array |
||
| 1804 | } |
||
| 1805 | } |
||
| 1806 |