| Total Complexity | 228 |
| Total Lines | 1210 |
| Duplicated Lines | 4.96 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
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 |
||
| 64 | abstract class ImportExport |
||
| 65 | { |
||
| 66 | /** |
||
| 67 | * If set, static relations (not exported) will be shown in overview as well |
||
| 68 | * |
||
| 69 | * @var bool |
||
| 70 | */ |
||
| 71 | public $showStaticRelations = false; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Name of the "fileadmin" folder where files for export/import should be located |
||
| 75 | * |
||
| 76 | * @var string |
||
| 77 | */ |
||
| 78 | public $fileadminFolderName = ''; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Whether "import" or "export" mode of object. Set through init() function |
||
| 82 | * |
||
| 83 | * @var string |
||
| 84 | */ |
||
| 85 | public $mode = ''; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * Updates all records that has same UID instead of creating new! |
||
| 89 | * |
||
| 90 | * @var bool |
||
| 91 | */ |
||
| 92 | public $update = false; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Is set by importData() when an import has been done. |
||
| 96 | * |
||
| 97 | * @var bool |
||
| 98 | */ |
||
| 99 | public $doesImport = false; |
||
| 100 | |||
| 101 | /** |
||
| 102 | * If set to a page-record, then the preview display of the content will expect this page-record to be the target |
||
| 103 | * for the import and accordingly display validation information. This triggers the visual view of the |
||
| 104 | * import/export memory to validate if import is possible |
||
| 105 | * |
||
| 106 | * @var array |
||
| 107 | */ |
||
| 108 | public $display_import_pid_record = []; |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Setting import modes during update state: as_new, exclude, force_uid |
||
| 112 | * |
||
| 113 | * @var array |
||
| 114 | */ |
||
| 115 | public $import_mode = []; |
||
| 116 | |||
| 117 | /** |
||
| 118 | * If set, PID correct is ignored globally |
||
| 119 | * |
||
| 120 | * @var bool |
||
| 121 | */ |
||
| 122 | public $global_ignore_pid = false; |
||
| 123 | |||
| 124 | /** |
||
| 125 | * If set, all UID values are forced! (update or import) |
||
| 126 | * |
||
| 127 | * @var bool |
||
| 128 | */ |
||
| 129 | public $force_all_UIDS = false; |
||
| 130 | |||
| 131 | /** |
||
| 132 | * If set, a diff-view column is added to the overview. |
||
| 133 | * |
||
| 134 | * @var bool |
||
| 135 | */ |
||
| 136 | public $showDiff = false; |
||
| 137 | |||
| 138 | /** |
||
| 139 | * If set, and if the user is admin, allow the writing of PHP scripts to fileadmin/ area. |
||
| 140 | * |
||
| 141 | * @var bool |
||
| 142 | */ |
||
| 143 | public $allowPHPScripts = false; |
||
| 144 | |||
| 145 | /** |
||
| 146 | * Array of values to substitute in editable softreferences. |
||
| 147 | * |
||
| 148 | * @var array |
||
| 149 | */ |
||
| 150 | public $softrefInputValues = []; |
||
| 151 | |||
| 152 | /** |
||
| 153 | * Mapping between the fileID from import memory and the final filenames they are written to. |
||
| 154 | * |
||
| 155 | * @var array |
||
| 156 | */ |
||
| 157 | public $fileIDMap = []; |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Add table names here which are THE ONLY ones which will be included |
||
| 161 | * into export if found as relations. '_ALL' will allow all tables. |
||
| 162 | * |
||
| 163 | * @var array |
||
| 164 | */ |
||
| 165 | public $relOnlyTables = []; |
||
| 166 | |||
| 167 | /** |
||
| 168 | * Add tables names here which should not be exported with the file. |
||
| 169 | * (Where relations should be mapped to same UIDs in target system). |
||
| 170 | * |
||
| 171 | * @var array |
||
| 172 | */ |
||
| 173 | public $relStaticTables = []; |
||
| 174 | |||
| 175 | /** |
||
| 176 | * Exclude map. Keys are table:uid pairs and if set, records are not added to the export. |
||
| 177 | * |
||
| 178 | * @var array |
||
| 179 | */ |
||
| 180 | public $excludeMap = []; |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Soft Reference Token ID modes. |
||
| 184 | * |
||
| 185 | * @var array |
||
| 186 | */ |
||
| 187 | public $softrefCfg = []; |
||
| 188 | |||
| 189 | /** |
||
| 190 | * Listing extension dependencies. |
||
| 191 | * |
||
| 192 | * @var array |
||
| 193 | */ |
||
| 194 | public $extensionDependencies = []; |
||
| 195 | |||
| 196 | /** |
||
| 197 | * After records are written this array is filled with [table][original_uid] = [new_uid] |
||
| 198 | * |
||
| 199 | * @var array |
||
| 200 | */ |
||
| 201 | public $import_mapId = []; |
||
| 202 | |||
| 203 | /** |
||
| 204 | * Error log. |
||
| 205 | * |
||
| 206 | * @var array |
||
| 207 | */ |
||
| 208 | public $errorLog = []; |
||
| 209 | |||
| 210 | /** |
||
| 211 | * Cache for record paths |
||
| 212 | * |
||
| 213 | * @var array |
||
| 214 | */ |
||
| 215 | public $cache_getRecordPath = []; |
||
| 216 | |||
| 217 | /** |
||
| 218 | * Cache of checkPID values. |
||
| 219 | * |
||
| 220 | * @var array |
||
| 221 | */ |
||
| 222 | public $checkPID_cache = []; |
||
| 223 | |||
| 224 | /** |
||
| 225 | * Set internally if the gzcompress function exists |
||
| 226 | * Used by ImportExportController |
||
| 227 | * |
||
| 228 | * @var bool |
||
| 229 | */ |
||
| 230 | public $compress = false; |
||
| 231 | |||
| 232 | /** |
||
| 233 | * Internal import/export memory |
||
| 234 | * |
||
| 235 | * @var array |
||
| 236 | */ |
||
| 237 | public $dat = []; |
||
| 238 | |||
| 239 | /** |
||
| 240 | * File processing object |
||
| 241 | * |
||
| 242 | * @var ExtendedFileUtility |
||
| 243 | */ |
||
| 244 | protected $fileProcObj = null; |
||
| 245 | |||
| 246 | /** |
||
| 247 | * @var array |
||
| 248 | */ |
||
| 249 | protected $remainHeader = []; |
||
| 250 | |||
| 251 | /** |
||
| 252 | * @var IconFactory |
||
| 253 | */ |
||
| 254 | protected $iconFactory; |
||
| 255 | |||
| 256 | /** |
||
| 257 | * Flag to control whether all disabled records and their children are excluded (true) or included (false). Defaults |
||
| 258 | * to the old behaviour of including everything. |
||
| 259 | * |
||
| 260 | * @var bool |
||
| 261 | */ |
||
| 262 | protected $excludeDisabledRecords = false; |
||
| 263 | |||
| 264 | /** |
||
| 265 | * The constructor |
||
| 266 | */ |
||
| 267 | public function __construct() |
||
| 268 | { |
||
| 269 | $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class); |
||
| 270 | } |
||
| 271 | |||
| 272 | /************************** |
||
| 273 | * Initialize |
||
| 274 | *************************/ |
||
| 275 | |||
| 276 | /** |
||
| 277 | * Init the object, both import and export |
||
| 278 | */ |
||
| 279 | public function init() |
||
| 280 | { |
||
| 281 | $this->compress = function_exists('gzcompress'); |
||
| 282 | $this->fileadminFolderName = !empty($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) ? rtrim($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') : 'fileadmin'; |
||
| 283 | } |
||
| 284 | |||
| 285 | /******************************************************** |
||
| 286 | * Visual rendering of import/export memory, $this->dat |
||
| 287 | ********************************************************/ |
||
| 288 | |||
| 289 | /** |
||
| 290 | * Displays an overview of the header-content. |
||
| 291 | * |
||
| 292 | * @return array The view data |
||
| 293 | */ |
||
| 294 | public function displayContentOverview() |
||
| 295 | { |
||
| 296 | if (!isset($this->dat['header'])) { |
||
| 297 | return []; |
||
| 298 | } |
||
| 299 | // Check extension dependencies: |
||
| 300 | foreach ($this->dat['header']['extensionDependencies'] as $extKey) { |
||
| 301 | if (!empty($extKey) && !ExtensionManagementUtility::isLoaded($extKey)) { |
||
| 302 | $this->error('DEPENDENCY: The extension with key "' . $extKey . '" must be installed!'); |
||
| 303 | } |
||
| 304 | } |
||
| 305 | |||
| 306 | // Probably this is done to save memory space? |
||
| 307 | unset($this->dat['files']); |
||
| 308 | |||
| 309 | $viewData = []; |
||
| 310 | // Traverse header: |
||
| 311 | $this->remainHeader = $this->dat['header']; |
||
| 312 | // If there is a page tree set, show that: |
||
| 313 | if (is_array($this->dat['header']['pagetree'])) { |
||
| 314 | reset($this->dat['header']['pagetree']); |
||
| 315 | $lines = []; |
||
| 316 | $this->traversePageTree($this->dat['header']['pagetree'], $lines); |
||
| 317 | |||
| 318 | $viewData['dat'] = $this->dat; |
||
| 319 | $viewData['update'] = $this->update; |
||
| 320 | $viewData['showDiff'] = $this->showDiff; |
||
| 321 | View Code Duplication | if (!empty($lines)) { |
|
| 322 | foreach ($lines as &$r) { |
||
| 323 | $r['controls'] = $this->renderControls($r); |
||
| 324 | $r['fileSize'] = GeneralUtility::formatSize($r['size']); |
||
| 325 | $r['message'] = ($r['msg'] && !$this->doesImport ? '<span class="text-danger">' . htmlspecialchars($r['msg']) . '</span>' : ''); |
||
| 326 | } |
||
| 327 | $viewData['pagetreeLines'] = $lines; |
||
| 328 | } else { |
||
| 329 | $viewData['pagetreeLines'] = []; |
||
| 330 | } |
||
| 331 | } |
||
| 332 | // Print remaining records that were not contained inside the page tree: |
||
| 333 | if (is_array($this->remainHeader['records'])) { |
||
| 334 | $lines = []; |
||
| 335 | if (is_array($this->remainHeader['records']['pages'])) { |
||
| 336 | $this->traversePageRecords($this->remainHeader['records']['pages'], $lines); |
||
| 337 | } |
||
| 338 | $this->traverseAllRecords($this->remainHeader['records'], $lines); |
||
| 339 | View Code Duplication | if (!empty($lines)) { |
|
| 340 | foreach ($lines as &$r) { |
||
| 341 | $r['controls'] = $this->renderControls($r); |
||
| 342 | $r['fileSize'] = GeneralUtility::formatSize($r['size']); |
||
| 343 | $r['message'] = ($r['msg'] && !$this->doesImport ? '<span class="text-danger">' . htmlspecialchars($r['msg']) . '</span>' : ''); |
||
| 344 | } |
||
| 345 | $viewData['remainingRecords'] = $lines; |
||
| 346 | } |
||
| 347 | } |
||
| 348 | |||
| 349 | return $viewData; |
||
| 350 | } |
||
| 351 | |||
| 352 | /** |
||
| 353 | * Go through page tree for display |
||
| 354 | * |
||
| 355 | * @param array $pT Page tree array with uid/subrow (from ->dat[header][pagetree] |
||
| 356 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 357 | * @param string $preCode Pre-HTML code |
||
| 358 | */ |
||
| 359 | public function traversePageTree($pT, &$lines, $preCode = '') |
||
| 360 | { |
||
| 361 | foreach ($pT as $k => $v) { |
||
| 362 | if ($this->excludeDisabledRecords === true && !$this->isActive('pages', $k)) { |
||
| 363 | $this->excludePageAndRecords($k, $v); |
||
| 364 | continue; |
||
| 365 | } |
||
| 366 | |||
| 367 | // Add this page: |
||
| 368 | $this->singleRecordLines('pages', $k, $lines, $preCode); |
||
| 369 | // Subrecords: |
||
| 370 | View Code Duplication | if (is_array($this->dat['header']['pid_lookup'][$k])) { |
|
| 371 | foreach ($this->dat['header']['pid_lookup'][$k] as $t => $recUidArr) { |
||
| 372 | if ($t !== 'pages') { |
||
| 373 | foreach ($recUidArr as $ruid => $value) { |
||
| 374 | $this->singleRecordLines($t, $ruid, $lines, $preCode . ' '); |
||
| 375 | } |
||
| 376 | } |
||
| 377 | } |
||
| 378 | unset($this->remainHeader['pid_lookup'][$k]); |
||
| 379 | } |
||
| 380 | // Subpages, called recursively: |
||
| 381 | if (is_array($v['subrow'])) { |
||
| 382 | $this->traversePageTree($v['subrow'], $lines, $preCode . ' '); |
||
| 383 | } |
||
| 384 | } |
||
| 385 | } |
||
| 386 | |||
| 387 | /** |
||
| 388 | * Test whether a record is active (i.e. not hidden) |
||
| 389 | * |
||
| 390 | * @param string $table Name of the records' database table |
||
| 391 | * @param int $uid Database uid of the record |
||
| 392 | * @return bool true if the record is active, false otherwise |
||
| 393 | */ |
||
| 394 | protected function isActive($table, $uid) |
||
| 395 | { |
||
| 396 | return |
||
| 397 | !isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) |
||
| 398 | || !(bool)$this->dat['records'][$table . ':' . $uid]['data'][ |
||
| 399 | $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled'] |
||
| 400 | ]; |
||
| 401 | } |
||
| 402 | |||
| 403 | /** |
||
| 404 | * Exclude a page, its sub pages (recursively) and records placed in them from this import/export |
||
| 405 | * |
||
| 406 | * @param int $pageUid Uid of the page to exclude |
||
| 407 | * @param array $pageTree Page tree array with uid/subrow (from ->dat[header][pagetree] |
||
| 408 | */ |
||
| 409 | protected function excludePageAndRecords($pageUid, $pageTree) |
||
| 410 | { |
||
| 411 | // Prevent having this page appear in "remaining records" table |
||
| 412 | unset($this->remainHeader['records']['pages'][$pageUid]); |
||
| 413 | |||
| 414 | // Subrecords |
||
| 415 | if (is_array($this->dat['header']['pid_lookup'][$pageUid])) { |
||
| 416 | foreach ($this->dat['header']['pid_lookup'][$pageUid] as $table => $recordData) { |
||
| 417 | if ($table !== 'pages') { |
||
| 418 | foreach (array_keys($recordData) as $uid) { |
||
| 419 | unset($this->remainHeader['records'][$table][$uid]); |
||
| 420 | } |
||
| 421 | } |
||
| 422 | } |
||
| 423 | unset($this->remainHeader['pid_lookup'][$pageUid]); |
||
| 424 | } |
||
| 425 | // Subpages excluded recursively |
||
| 426 | if (is_array($pageTree['subrow'])) { |
||
| 427 | foreach ($pageTree['subrow'] as $subPageUid => $subPageTree) { |
||
| 428 | $this->excludePageAndRecords($subPageUid, $subPageTree); |
||
| 429 | } |
||
| 430 | } |
||
| 431 | } |
||
| 432 | |||
| 433 | /** |
||
| 434 | * Go through remaining pages (not in tree) |
||
| 435 | * |
||
| 436 | * @param array $pT Page tree array with uid/subrow (from ->dat[header][pagetree] |
||
| 437 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 438 | */ |
||
| 439 | public function traversePageRecords($pT, &$lines) |
||
| 440 | { |
||
| 441 | foreach ($pT as $k => $rHeader) { |
||
| 442 | $this->singleRecordLines('pages', $k, $lines, '', 1); |
||
| 443 | // Subrecords: |
||
| 444 | View Code Duplication | if (is_array($this->dat['header']['pid_lookup'][$k])) { |
|
| 445 | foreach ($this->dat['header']['pid_lookup'][$k] as $t => $recUidArr) { |
||
| 446 | if ($t !== 'pages') { |
||
| 447 | foreach ($recUidArr as $ruid => $value) { |
||
| 448 | $this->singleRecordLines($t, $ruid, $lines, ' '); |
||
| 449 | } |
||
| 450 | } |
||
| 451 | } |
||
| 452 | unset($this->remainHeader['pid_lookup'][$k]); |
||
| 453 | } |
||
| 454 | } |
||
| 455 | } |
||
| 456 | |||
| 457 | /** |
||
| 458 | * Go through ALL records (if the pages are displayed first, those will not be among these!) |
||
| 459 | * |
||
| 460 | * @param array $pT Page tree array with uid/subrow (from ->dat[header][pagetree] |
||
| 461 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 462 | */ |
||
| 463 | public function traverseAllRecords($pT, &$lines) |
||
| 464 | { |
||
| 465 | foreach ($pT as $t => $recUidArr) { |
||
| 466 | $this->addGeneralErrorsByTable($t); |
||
| 467 | if ($t !== 'pages') { |
||
| 468 | $preCode = ''; |
||
| 469 | foreach ($recUidArr as $ruid => $value) { |
||
| 470 | $this->singleRecordLines($t, $ruid, $lines, $preCode, 1); |
||
| 471 | } |
||
| 472 | } |
||
| 473 | } |
||
| 474 | } |
||
| 475 | |||
| 476 | /** |
||
| 477 | * Log general error message for a given table |
||
| 478 | * |
||
| 479 | * @param string $table database table name |
||
| 480 | */ |
||
| 481 | protected function addGeneralErrorsByTable($table) |
||
| 482 | { |
||
| 483 | if ($this->update && $table === 'sys_file') { |
||
| 484 | $this->error('Updating sys_file records is not supported! They will be imported as new records!'); |
||
| 485 | } |
||
| 486 | if ($this->force_all_UIDS && $table === 'sys_file') { |
||
| 487 | $this->error('Forcing uids of sys_file records is not supported! They will be imported as new records!'); |
||
| 488 | } |
||
| 489 | } |
||
| 490 | |||
| 491 | /** |
||
| 492 | * Add entries for a single record |
||
| 493 | * |
||
| 494 | * @param string $table Table name |
||
| 495 | * @param int $uid Record uid |
||
| 496 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 497 | * @param string $preCode Pre-HTML code |
||
| 498 | * @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. |
||
| 499 | */ |
||
| 500 | public function singleRecordLines($table, $uid, &$lines, $preCode, $checkImportInPidRecord = false) |
||
| 501 | { |
||
| 502 | // Get record: |
||
| 503 | $record = $this->dat['header']['records'][$table][$uid]; |
||
| 504 | unset($this->remainHeader['records'][$table][$uid]); |
||
| 505 | if (!is_array($record) && !($table === 'pages' && !$uid)) { |
||
| 506 | $this->error('MISSING RECORD: ' . $table . ':' . $uid); |
||
| 507 | } |
||
| 508 | // Begin to create the line arrays information record, pInfo: |
||
| 509 | $pInfo = []; |
||
| 510 | $pInfo['ref'] = $table . ':' . $uid; |
||
| 511 | // Unknown table name: |
||
| 512 | $lang = $this->getLanguageService(); |
||
| 513 | if ($table === '_SOFTREF_') { |
||
| 514 | $pInfo['preCode'] = $preCode; |
||
| 515 | $pInfo['title'] = '<em>' . htmlspecialchars($lang->getLL('impexpcore_singlereco_softReferencesFiles')) . '</em>'; |
||
| 516 | } elseif (!isset($GLOBALS['TCA'][$table])) { |
||
| 517 | // Unknown table name: |
||
| 518 | $pInfo['preCode'] = $preCode; |
||
| 519 | $pInfo['msg'] = 'UNKNOWN TABLE \'' . $pInfo['ref'] . '\''; |
||
| 520 | $pInfo['title'] = '<em>' . htmlspecialchars($record['title']) . '</em>'; |
||
| 521 | } else { |
||
| 522 | // prepare data attribute telling whether the record is active or hidden, allowing frontend bulk selection |
||
| 523 | $pInfo['active'] = $this->isActive($table, $uid) ? 'active' : 'hidden'; |
||
| 524 | |||
| 525 | // Otherwise, set table icon and title. |
||
| 526 | // Import Validation (triggered by $this->display_import_pid_record) will show messages if import is not possible of various items. |
||
| 527 | if (is_array($this->display_import_pid_record) && !empty($this->display_import_pid_record)) { |
||
| 528 | if ($checkImportInPidRecord) { |
||
| 529 | if (!$this->getBackendUser()->doesUserHaveAccess($this->display_import_pid_record, ($table === 'pages' ? 8 : 16))) { |
||
| 530 | $pInfo['msg'] .= '\'' . $pInfo['ref'] . '\' cannot be INSERTED on this page! '; |
||
| 531 | } |
||
| 532 | if (!$this->checkDokType($table, $this->display_import_pid_record['doktype']) && !$GLOBALS['TCA'][$table]['ctrl']['rootLevel']) { |
||
| 533 | $pInfo['msg'] .= '\'' . $table . '\' cannot be INSERTED on this page type (change page type to \'Folder\'.) '; |
||
| 534 | } |
||
| 535 | } |
||
| 536 | if (!$this->getBackendUser()->check('tables_modify', $table)) { |
||
| 537 | $pInfo['msg'] .= 'You are not allowed to CREATE \'' . $table . '\' tables! '; |
||
| 538 | } |
||
| 539 | if ($GLOBALS['TCA'][$table]['ctrl']['readOnly']) { |
||
| 540 | $pInfo['msg'] .= 'TABLE \'' . $table . '\' is READ ONLY! '; |
||
| 541 | } |
||
| 542 | if ($GLOBALS['TCA'][$table]['ctrl']['adminOnly'] && !$this->getBackendUser()->isAdmin()) { |
||
| 543 | $pInfo['msg'] .= 'TABLE \'' . $table . '\' is ADMIN ONLY! '; |
||
| 544 | } |
||
| 545 | if ($GLOBALS['TCA'][$table]['ctrl']['is_static']) { |
||
| 546 | $pInfo['msg'] .= 'TABLE \'' . $table . '\' is a STATIC TABLE! '; |
||
| 547 | } |
||
| 548 | if ((int)$GLOBALS['TCA'][$table]['ctrl']['rootLevel'] === 1) { |
||
| 549 | $pInfo['msg'] .= 'TABLE \'' . $table . '\' will be inserted on ROOT LEVEL! '; |
||
| 550 | } |
||
| 551 | $diffInverse = false; |
||
| 552 | $recInf = null; |
||
| 553 | if ($this->update) { |
||
| 554 | // In case of update-PREVIEW we swap the diff-sources. |
||
| 555 | $diffInverse = true; |
||
| 556 | $recInf = $this->doesRecordExist($table, $uid, $this->showDiff ? '*' : ''); |
||
| 557 | $pInfo['updatePath'] = $recInf ? htmlspecialchars($this->getRecordPath($recInf['pid'])) : '<strong>NEW!</strong>'; |
||
| 558 | // Mode selector: |
||
| 559 | $optValues = []; |
||
| 560 | $optValues[] = $recInf ? $lang->getLL('impexpcore_singlereco_update') : $lang->getLL('impexpcore_singlereco_insert'); |
||
| 561 | if ($recInf) { |
||
|
|
|||
| 562 | $optValues['as_new'] = $lang->getLL('impexpcore_singlereco_importAsNew'); |
||
| 563 | } |
||
| 564 | if ($recInf) { |
||
| 565 | if (!$this->global_ignore_pid) { |
||
| 566 | $optValues['ignore_pid'] = $lang->getLL('impexpcore_singlereco_ignorePid'); |
||
| 567 | } else { |
||
| 568 | $optValues['respect_pid'] = $lang->getLL('impexpcore_singlereco_respectPid'); |
||
| 569 | } |
||
| 570 | } |
||
| 571 | if (!$recInf && $this->getBackendUser()->isAdmin()) { |
||
| 572 | $optValues['force_uid'] = sprintf($lang->getLL('impexpcore_singlereco_forceUidSAdmin'), $uid); |
||
| 573 | } |
||
| 574 | $optValues['exclude'] = $lang->getLL('impexpcore_singlereco_exclude'); |
||
| 575 | if ($table === 'sys_file') { |
||
| 576 | $pInfo['updateMode'] = ''; |
||
| 577 | } else { |
||
| 578 | $pInfo['updateMode'] = $this->renderSelectBox('tx_impexp[import_mode][' . $table . ':' . $uid . ']', $this->import_mode[$table . ':' . $uid], $optValues); |
||
| 579 | } |
||
| 580 | } |
||
| 581 | // Diff view: |
||
| 582 | if ($this->showDiff) { |
||
| 583 | // For IMPORTS, get new id: |
||
| 584 | if ($newUid = $this->import_mapId[$table][$uid]) { |
||
| 585 | $diffInverse = false; |
||
| 586 | $recInf = $this->doesRecordExist($table, $newUid, '*'); |
||
| 587 | BackendUtility::workspaceOL($table, $recInf); |
||
| 588 | } |
||
| 589 | if (is_array($recInf)) { |
||
| 590 | $pInfo['showDiffContent'] = $this->compareRecords($recInf, $this->dat['records'][$table . ':' . $uid]['data'], $table, $diffInverse); |
||
| 591 | } |
||
| 592 | } |
||
| 593 | } |
||
| 594 | $pInfo['preCode'] = $preCode . '<span title="' . htmlspecialchars($table . ':' . $uid) . '">' |
||
| 595 | . $this->iconFactory->getIconForRecord($table, (array)$this->dat['records'][$table . ':' . $uid]['data'], Icon::SIZE_SMALL)->render() |
||
| 596 | . '</span>'; |
||
| 597 | $pInfo['title'] = htmlspecialchars($record['title']); |
||
| 598 | // View page: |
||
| 599 | if ($table === 'pages') { |
||
| 600 | $viewID = $this->mode === 'export' ? $uid : ($this->doesImport ? $this->import_mapId['pages'][$uid] : 0); |
||
| 601 | if ($viewID) { |
||
| 602 | $pInfo['title'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($viewID)) . 'return false;">' . $pInfo['title'] . '</a>'; |
||
| 603 | } |
||
| 604 | } |
||
| 605 | } |
||
| 606 | $pInfo['type'] = 'record'; |
||
| 607 | $pInfo['size'] = (int)$record['size']; |
||
| 608 | $lines[] = $pInfo; |
||
| 609 | // File relations: |
||
| 610 | if (is_array($record['filerefs'])) { |
||
| 611 | $this->addFiles($record['filerefs'], $lines, $preCode); |
||
| 612 | } |
||
| 613 | // DB relations |
||
| 614 | if (is_array($record['rels'])) { |
||
| 615 | $this->addRelations($record['rels'], $lines, $preCode); |
||
| 616 | } |
||
| 617 | // Soft ref |
||
| 618 | if (!empty($record['softrefs'])) { |
||
| 619 | $preCode_A = $preCode . ' '; |
||
| 620 | $preCode_B = $preCode . ' '; |
||
| 621 | foreach ($record['softrefs'] as $info) { |
||
| 622 | $pInfo = []; |
||
| 623 | $pInfo['preCode'] = $preCode_A . $this->iconFactory->getIcon('status-reference-soft', Icon::SIZE_SMALL)->render(); |
||
| 624 | $pInfo['title'] = '<em>' . $info['field'] . ', "' . $info['spKey'] . '" </em>: <span title="' . htmlspecialchars($info['matchString']) . '">' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($info['matchString'], 60)) . '</span>'; |
||
| 625 | if ($info['subst']['type']) { |
||
| 626 | View Code Duplication | if (strlen($info['subst']['title'])) { |
|
| 627 | $pInfo['title'] .= '<br/>' . $preCode_B . '<strong>' . htmlspecialchars($lang->getLL('impexpcore_singlereco_title')) . '</strong> ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($info['subst']['title'], 60)); |
||
| 628 | } |
||
| 629 | View Code Duplication | if (strlen($info['subst']['description'])) { |
|
| 630 | $pInfo['title'] .= '<br/>' . $preCode_B . '<strong>' . htmlspecialchars($lang->getLL('impexpcore_singlereco_descr')) . '</strong> ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($info['subst']['description'], 60)); |
||
| 631 | } |
||
| 632 | $pInfo['title'] .= '<br/>' . $preCode_B . ($info['subst']['type'] === 'file' ? htmlspecialchars($lang->getLL('impexpcore_singlereco_filename')) . ' <strong>' . $info['subst']['relFileName'] . '</strong>' : '') . ($info['subst']['type'] === 'string' ? htmlspecialchars($lang->getLL('impexpcore_singlereco_value')) . ' <strong>' . $info['subst']['tokenValue'] . '</strong>' : '') . ($info['subst']['type'] === 'db' ? htmlspecialchars($lang->getLL('impexpcore_softrefsel_record')) . ' <strong>' . $info['subst']['recordRef'] . '</strong>' : ''); |
||
| 633 | } |
||
| 634 | $pInfo['ref'] = 'SOFTREF'; |
||
| 635 | $pInfo['size'] = 0; |
||
| 636 | $pInfo['type'] = 'softref'; |
||
| 637 | $pInfo['_softRefInfo'] = $info; |
||
| 638 | $pInfo['type'] = 'softref'; |
||
| 639 | $mode = $this->softrefCfg[$info['subst']['tokenID']]['mode']; |
||
| 640 | if ($info['error'] && $mode !== 'editable' && $mode !== 'exclude') { |
||
| 641 | $pInfo['msg'] .= $info['error']; |
||
| 642 | } |
||
| 643 | $lines[] = $pInfo; |
||
| 644 | // Add relations: |
||
| 645 | if ($info['subst']['type'] === 'db') { |
||
| 646 | list($tempTable, $tempUid) = explode(':', $info['subst']['recordRef']); |
||
| 647 | $this->addRelations([['table' => $tempTable, 'id' => $tempUid, 'tokenID' => $info['subst']['tokenID']]], $lines, $preCode_B, [], ''); |
||
| 648 | } |
||
| 649 | // Add files: |
||
| 650 | if ($info['subst']['type'] === 'file') { |
||
| 651 | $this->addFiles([$info['file_ID']], $lines, $preCode_B, '', $info['subst']['tokenID']); |
||
| 652 | } |
||
| 653 | } |
||
| 654 | } |
||
| 655 | } |
||
| 656 | |||
| 657 | /** |
||
| 658 | * Add DB relations entries for a record's rels-array |
||
| 659 | * |
||
| 660 | * @param array $rels Array of relations |
||
| 661 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 662 | * @param string $preCode Pre-HTML code |
||
| 663 | * @param array $recurCheck Recursivity check stack |
||
| 664 | * @param string $htmlColorClass Alternative HTML color class to use. |
||
| 665 | * @access private |
||
| 666 | * @see singleRecordLines() |
||
| 667 | */ |
||
| 668 | public function addRelations($rels, &$lines, $preCode, $recurCheck = [], $htmlColorClass = '') |
||
| 669 | { |
||
| 670 | foreach ($rels as $dat) { |
||
| 671 | $table = $dat['table']; |
||
| 672 | $uid = $dat['id']; |
||
| 673 | $pInfo = []; |
||
| 674 | $pInfo['ref'] = $table . ':' . $uid; |
||
| 675 | if (in_array($pInfo['ref'], $recurCheck)) { |
||
| 676 | continue; |
||
| 677 | } |
||
| 678 | $iconName = 'status-status-checked'; |
||
| 679 | $iconClass = ''; |
||
| 680 | $staticFixed = false; |
||
| 681 | $record = null; |
||
| 682 | if ($uid > 0) { |
||
| 683 | $record = $this->dat['header']['records'][$table][$uid]; |
||
| 684 | if (!is_array($record)) { |
||
| 685 | if ($this->isTableStatic($table) || $this->isExcluded($table, $uid) || $dat['tokenID'] && !$this->includeSoftref($dat['tokenID'])) { |
||
| 686 | $pInfo['title'] = htmlspecialchars('STATIC: ' . $pInfo['ref']); |
||
| 687 | $iconClass = 'text-info'; |
||
| 688 | $staticFixed = true; |
||
| 689 | } else { |
||
| 690 | $doesRE = $this->doesRecordExist($table, $uid); |
||
| 691 | $lostPath = $this->getRecordPath($table === 'pages' ? $doesRE['uid'] : $doesRE['pid']); |
||
| 692 | $pInfo['title'] = htmlspecialchars($pInfo['ref']); |
||
| 693 | $pInfo['title'] = '<span title="' . htmlspecialchars($lostPath) . '">' . $pInfo['title'] . '</span>'; |
||
| 694 | $pInfo['msg'] = 'LOST RELATION' . (!$doesRE ? ' (Record not found!)' : ' (Path: ' . $lostPath . ')'); |
||
| 695 | $iconClass = 'text-danger'; |
||
| 696 | $iconName = 'status-dialog-warning'; |
||
| 697 | } |
||
| 698 | } else { |
||
| 699 | $pInfo['title'] = htmlspecialchars($record['title']); |
||
| 700 | $pInfo['title'] = '<span title="' . htmlspecialchars($this->getRecordPath(($table === 'pages' ? $record['uid'] : $record['pid']))) . '">' . $pInfo['title'] . '</span>'; |
||
| 701 | } |
||
| 702 | } else { |
||
| 703 | // Negative values in relation fields. This is typically sys_language fields, fe_users fields etc. They are static values. They CAN theoretically be negative pointers to uids in other tables but this is so rarely used that it is not supported |
||
| 704 | $pInfo['title'] = htmlspecialchars('FIXED: ' . $pInfo['ref']); |
||
| 705 | $staticFixed = true; |
||
| 706 | } |
||
| 707 | |||
| 708 | $icon = '<span class="' . $iconClass . '" title="' . htmlspecialchars($pInfo['ref']) . '">' . $this->iconFactory->getIcon($iconName, Icon::SIZE_SMALL)->render() . '</span>'; |
||
| 709 | |||
| 710 | $pInfo['preCode'] = $preCode . ' ' . $icon; |
||
| 711 | $pInfo['type'] = 'rel'; |
||
| 712 | if (!$staticFixed || $this->showStaticRelations) { |
||
| 713 | $lines[] = $pInfo; |
||
| 714 | if (is_array($record) && is_array($record['rels'])) { |
||
| 715 | $this->addRelations($record['rels'], $lines, $preCode . ' ', array_merge($recurCheck, [$pInfo['ref']])); |
||
| 716 | } |
||
| 717 | } |
||
| 718 | } |
||
| 719 | } |
||
| 720 | |||
| 721 | /** |
||
| 722 | * Add file relation entries for a record's rels-array |
||
| 723 | * |
||
| 724 | * @param array $rels Array of file IDs |
||
| 725 | * @param array $lines Output lines array (is passed by reference and modified) |
||
| 726 | * @param string $preCode Pre-HTML code |
||
| 727 | * @param string $htmlColorClass Alternative HTML color class to use. |
||
| 728 | * @param string $tokenID Token ID if this is a softreference (in which case it only makes sense with a single element in the $rels array!) |
||
| 729 | * @access private |
||
| 730 | * @see singleRecordLines() |
||
| 731 | */ |
||
| 732 | public function addFiles($rels, &$lines, $preCode, $htmlColorClass = '', $tokenID = '') |
||
| 733 | { |
||
| 734 | foreach ($rels as $ID) { |
||
| 735 | // Process file: |
||
| 736 | $pInfo = []; |
||
| 737 | $fI = $this->dat['header']['files'][$ID]; |
||
| 738 | if (!is_array($fI)) { |
||
| 739 | if (!$tokenID || $this->includeSoftref($tokenID)) { |
||
| 740 | $pInfo['msg'] = 'MISSING FILE: ' . $ID; |
||
| 741 | $this->error('MISSING FILE: ' . $ID); |
||
| 742 | } else { |
||
| 743 | return; |
||
| 744 | } |
||
| 745 | } |
||
| 746 | $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('status-reference-hard', Icon::SIZE_SMALL)->render(); |
||
| 747 | $pInfo['title'] = htmlspecialchars($fI['filename']); |
||
| 748 | $pInfo['ref'] = 'FILE'; |
||
| 749 | $pInfo['size'] = $fI['filesize']; |
||
| 750 | $pInfo['type'] = 'file'; |
||
| 751 | // If import mode and there is a non-RTE softreference, check the destination directory: |
||
| 752 | if ($this->mode === 'import' && $tokenID && !$fI['RTE_ORIG_ID']) { |
||
| 753 | if (isset($fI['parentRelFileName'])) { |
||
| 754 | $pInfo['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. '; |
||
| 755 | } else { |
||
| 756 | $testDirPrefix = PathUtility::dirname($fI['relFileName']) . '/'; |
||
| 757 | $testDirPrefix2 = $this->verifyFolderAccess($testDirPrefix); |
||
| 758 | if (!$testDirPrefix2) { |
||
| 759 | $pInfo['msg'] = 'ERROR: There are no available filemounts to write file in! '; |
||
| 760 | } elseif ($testDirPrefix !== $testDirPrefix2) { |
||
| 761 | $pInfo['msg'] = 'File will be attempted written to "' . $testDirPrefix2 . '". '; |
||
| 762 | } |
||
| 763 | } |
||
| 764 | // Check if file exists: |
||
| 765 | if (file_exists(PATH_site . $fI['relFileName'])) { |
||
| 766 | if ($this->update) { |
||
| 767 | $pInfo['updatePath'] .= 'File exists.'; |
||
| 768 | } else { |
||
| 769 | $pInfo['msg'] .= 'File already exists! '; |
||
| 770 | } |
||
| 771 | } |
||
| 772 | // Check extension: |
||
| 773 | $fileProcObj = $this->getFileProcObj(); |
||
| 774 | if ($fileProcObj->actionPerms['addFile']) { |
||
| 775 | $testFI = GeneralUtility::split_fileref(PATH_site . $fI['relFileName']); |
||
| 776 | if (!$this->allowPHPScripts && !$fileProcObj->checkIfAllowed($testFI['fileext'], $testFI['path'], $testFI['file'])) { |
||
| 777 | $pInfo['msg'] .= 'File extension was not allowed!'; |
||
| 778 | } |
||
| 779 | } else { |
||
| 780 | $pInfo['msg'] = 'You user profile does not allow you to create files on the server!'; |
||
| 781 | } |
||
| 782 | } |
||
| 783 | $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$ID]); |
||
| 784 | $lines[] = $pInfo; |
||
| 785 | unset($this->remainHeader['files'][$ID]); |
||
| 786 | // RTE originals: |
||
| 787 | if ($fI['RTE_ORIG_ID']) { |
||
| 788 | $ID = $fI['RTE_ORIG_ID']; |
||
| 789 | $pInfo = []; |
||
| 790 | $fI = $this->dat['header']['files'][$ID]; |
||
| 791 | if (!is_array($fI)) { |
||
| 792 | $pInfo['msg'] = 'MISSING RTE original FILE: ' . $ID; |
||
| 793 | $this->error('MISSING RTE original FILE: ' . $ID); |
||
| 794 | } |
||
| 795 | $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$ID]); |
||
| 796 | $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('status-reference-hard', Icon::SIZE_SMALL)->render(); |
||
| 797 | $pInfo['title'] = htmlspecialchars($fI['filename']) . ' <em>(Original)</em>'; |
||
| 798 | $pInfo['ref'] = 'FILE'; |
||
| 799 | $pInfo['size'] = $fI['filesize']; |
||
| 800 | $pInfo['type'] = 'file'; |
||
| 801 | $lines[] = $pInfo; |
||
| 802 | unset($this->remainHeader['files'][$ID]); |
||
| 803 | } |
||
| 804 | // External resources: |
||
| 805 | if (is_array($fI['EXT_RES_ID'])) { |
||
| 806 | foreach ($fI['EXT_RES_ID'] as $extID) { |
||
| 807 | $pInfo = []; |
||
| 808 | $fI = $this->dat['header']['files'][$extID]; |
||
| 809 | if (!is_array($fI)) { |
||
| 810 | $pInfo['msg'] = 'MISSING External Resource FILE: ' . $extID; |
||
| 811 | $this->error('MISSING External Resource FILE: ' . $extID); |
||
| 812 | } else { |
||
| 813 | $pInfo['updatePath'] = $fI['parentRelFileName']; |
||
| 814 | } |
||
| 815 | $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$extID]); |
||
| 816 | $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('actions-insert-reference', Icon::SIZE_SMALL)->render(); |
||
| 817 | $pInfo['title'] = htmlspecialchars($fI['filename']) . ' <em>(Resource)</em>'; |
||
| 818 | $pInfo['ref'] = 'FILE'; |
||
| 819 | $pInfo['size'] = $fI['filesize']; |
||
| 820 | $pInfo['type'] = 'file'; |
||
| 821 | $lines[] = $pInfo; |
||
| 822 | unset($this->remainHeader['files'][$extID]); |
||
| 823 | } |
||
| 824 | } |
||
| 825 | } |
||
| 826 | } |
||
| 827 | |||
| 828 | /** |
||
| 829 | * Verifies that a table is allowed on a certain doktype of a page |
||
| 830 | * |
||
| 831 | * @param string $checkTable Table name to check |
||
| 832 | * @param int $doktype doktype value. |
||
| 833 | * @return bool TRUE if OK |
||
| 834 | */ |
||
| 835 | public function checkDokType($checkTable, $doktype) |
||
| 836 | { |
||
| 837 | $allowedTableList = isset($GLOBALS['PAGES_TYPES'][$doktype]['allowedTables']) ? $GLOBALS['PAGES_TYPES'][$doktype]['allowedTables'] : $GLOBALS['PAGES_TYPES']['default']['allowedTables']; |
||
| 838 | $allowedArray = GeneralUtility::trimExplode(',', $allowedTableList, true); |
||
| 839 | // If all tables or the table is listed as an allowed type, return TRUE |
||
| 840 | if (strstr($allowedTableList, '*') || in_array($checkTable, $allowedArray)) { |
||
| 841 | return true; |
||
| 842 | } |
||
| 843 | return false; |
||
| 844 | } |
||
| 845 | |||
| 846 | /** |
||
| 847 | * Render input controls for import or export |
||
| 848 | * |
||
| 849 | * @param array $r Configuration for element |
||
| 850 | * @return string HTML |
||
| 851 | */ |
||
| 852 | public function renderControls($r) |
||
| 853 | { |
||
| 854 | if ($this->mode === 'export') { |
||
| 855 | if ($r['type'] === 'record') { |
||
| 856 | return '<input type="checkbox" class="t3js-exclude-checkbox" name="tx_impexp[exclude][' . $r['ref'] . ']" id="checkExclude' . $r['ref'] . '" value="1" /> <label for="checkExclude' . $r['ref'] . '">' . htmlspecialchars($this->getLanguageService()->getLL('impexpcore_singlereco_exclude')) . '</label>'; |
||
| 857 | } |
||
| 858 | return $r['type'] === 'softref' ? $this->softrefSelector($r['_softRefInfo']) : ''; |
||
| 859 | } |
||
| 860 | // During import |
||
| 861 | // For softreferences with editable fields: |
||
| 862 | if ($r['type'] === 'softref' && is_array($r['_softRefInfo']['subst']) && $r['_softRefInfo']['subst']['tokenID']) { |
||
| 863 | $tokenID = $r['_softRefInfo']['subst']['tokenID']; |
||
| 864 | $cfg = $this->softrefCfg[$tokenID]; |
||
| 865 | if ($cfg['mode'] === 'editable') { |
||
| 866 | return (strlen($cfg['title']) ? '<strong>' . htmlspecialchars($cfg['title']) . '</strong><br/>' : '') . htmlspecialchars($cfg['description']) . '<br/> |
||
| 867 | <input type="text" name="tx_impexp[softrefInputValues][' . $tokenID . ']" value="' . htmlspecialchars((isset($this->softrefInputValues[$tokenID]) ? $this->softrefInputValues[$tokenID] : $cfg['defValue'])) . '" />'; |
||
| 868 | } |
||
| 869 | } |
||
| 870 | |||
| 871 | return ''; |
||
| 872 | } |
||
| 873 | |||
| 874 | /** |
||
| 875 | * Selectorbox with export options for soft references |
||
| 876 | * |
||
| 877 | * @param array $cfg Softref configuration array. An export box is shown only if a substitution scheme is found for the soft reference. |
||
| 878 | * @return string Selector box HTML |
||
| 879 | */ |
||
| 880 | public function softrefSelector($cfg) |
||
| 921 | } |
||
| 922 | |||
| 923 | /** |
||
| 924 | * Verifies that the input path (relative to PATH_site) is found in the backend users filemounts. |
||
| 925 | * If it doesn't it will try to find another relative filemount for the user and return an alternative path prefix for the file. |
||
| 926 | * |
||
| 927 | * @param string $dirPrefix Path relative to PATH_site |
||
| 928 | * @param bool $noAlternative If set, Do not look for alternative path! Just return FALSE |
||
| 929 | * @return string|bool If a path is available that will be returned, otherwise FALSE. |
||
| 930 | */ |
||
| 931 | public function verifyFolderAccess($dirPrefix, $noAlternative = false) |
||
| 932 | { |
||
| 933 | // Check the absolute path for PATH_site, if the user has access - no problem |
||
| 934 | try { |
||
| 935 | ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($dirPrefix); |
||
| 936 | return $dirPrefix; |
||
| 937 | } catch (InsufficientFolderAccessPermissionsException $e) { |
||
| 938 | // Check all storages available for the user as alternative |
||
| 939 | if (!$noAlternative) { |
||
| 940 | $fileStorages = $this->getBackendUser()->getFileStorages(); |
||
| 941 | foreach ($fileStorages as $fileStorage) { |
||
| 942 | try { |
||
| 943 | $folder = $fileStorage->getFolder(rtrim($dirPrefix, '/')); |
||
| 944 | return $folder->getPublicUrl(); |
||
| 945 | } catch (InsufficientFolderAccessPermissionsException $e) { |
||
| 946 | } |
||
| 947 | } |
||
| 948 | } |
||
| 949 | } |
||
| 950 | return false; |
||
| 951 | } |
||
| 952 | |||
| 953 | /***************************** |
||
| 954 | * Helper functions of kinds |
||
| 955 | *****************************/ |
||
| 956 | |||
| 957 | /** |
||
| 958 | * @return string |
||
| 959 | */ |
||
| 960 | protected function getTemporaryFolderName() |
||
| 961 | { |
||
| 962 | $temporaryPath = PATH_site . 'typo3temp/var/transient/'; |
||
| 963 | do { |
||
| 964 | $temporaryFolderName = $temporaryPath . 'export_temp_files_' . mt_rand(1, PHP_INT_MAX); |
||
| 965 | } while (is_dir($temporaryFolderName)); |
||
| 966 | GeneralUtility::mkdir($temporaryFolderName); |
||
| 967 | return $temporaryFolderName; |
||
| 968 | } |
||
| 969 | |||
| 970 | /** |
||
| 971 | * Recursively flattening the idH array |
||
| 972 | * |
||
| 973 | * @param array $idH Page uid hierarchy |
||
| 974 | * @param array $a Accumulation array of pages (internal, don't set from outside) |
||
| 975 | * @return array Array with uid-uid pairs for all pages in the page tree. |
||
| 976 | * @see Import::flatInversePageTree_pid() |
||
| 977 | */ |
||
| 978 | View Code Duplication | public function flatInversePageTree($idH, $a = []) |
|
| 979 | { |
||
| 980 | if (is_array($idH)) { |
||
| 981 | $idH = array_reverse($idH); |
||
| 982 | foreach ($idH as $k => $v) { |
||
| 983 | $a[$v['uid']] = $v['uid']; |
||
| 984 | if (is_array($v['subrow'])) { |
||
| 985 | $a = $this->flatInversePageTree($v['subrow'], $a); |
||
| 986 | } |
||
| 987 | } |
||
| 988 | } |
||
| 989 | return $a; |
||
| 990 | } |
||
| 991 | |||
| 992 | /** |
||
| 993 | * Returns TRUE if the input table name is to be regarded as a static relation (that is, not exported etc). |
||
| 994 | * |
||
| 995 | * @param string $table Table name |
||
| 996 | * @return bool TRUE, if table is marked static |
||
| 997 | */ |
||
| 998 | public function isTableStatic($table) |
||
| 999 | { |
||
| 1000 | if (is_array($GLOBALS['TCA'][$table])) { |
||
| 1001 | return $GLOBALS['TCA'][$table]['ctrl']['is_static'] || in_array($table, $this->relStaticTables) || in_array('_ALL', $this->relStaticTables); |
||
| 1002 | } |
||
| 1003 | return false; |
||
| 1004 | } |
||
| 1005 | |||
| 1006 | /** |
||
| 1007 | * Returns TRUE if the input table name is to be included as relation |
||
| 1008 | * |
||
| 1009 | * @param string $table Table name |
||
| 1010 | * @return bool TRUE, if table is marked static |
||
| 1011 | */ |
||
| 1012 | public function inclRelation($table) |
||
| 1013 | { |
||
| 1014 | return is_array($GLOBALS['TCA'][$table]) |
||
| 1015 | && (in_array($table, $this->relOnlyTables) || in_array('_ALL', $this->relOnlyTables)) |
||
| 1016 | && $this->getBackendUser()->check('tables_select', $table); |
||
| 1017 | } |
||
| 1018 | |||
| 1019 | /** |
||
| 1020 | * Returns TRUE if the element should be excluded as static record. |
||
| 1021 | * |
||
| 1022 | * @param string $table Table name |
||
| 1023 | * @param int $uid UID value |
||
| 1024 | * @return bool TRUE, if table is marked static |
||
| 1025 | */ |
||
| 1026 | public function isExcluded($table, $uid) |
||
| 1027 | { |
||
| 1028 | return (bool)$this->excludeMap[$table . ':' . $uid]; |
||
| 1029 | } |
||
| 1030 | |||
| 1031 | /** |
||
| 1032 | * Returns TRUE if soft reference should be included in exported file. |
||
| 1033 | * |
||
| 1034 | * @param string $tokenID Token ID for soft reference |
||
| 1035 | * @return bool TRUE if softreference media should be included |
||
| 1036 | */ |
||
| 1037 | public function includeSoftref($tokenID) |
||
| 1038 | { |
||
| 1039 | $mode = $this->softrefCfg[$tokenID]['mode']; |
||
| 1040 | return $tokenID && $mode !== 'exclude' && $mode !== 'editable'; |
||
| 1041 | } |
||
| 1042 | |||
| 1043 | /** |
||
| 1044 | * Checking if a PID is in the webmounts of the user |
||
| 1045 | * |
||
| 1046 | * @param int $pid Page ID to check |
||
| 1047 | * @return bool TRUE if OK |
||
| 1048 | */ |
||
| 1049 | public function checkPID($pid) |
||
| 1050 | { |
||
| 1051 | if (!isset($this->checkPID_cache[$pid])) { |
||
| 1052 | $this->checkPID_cache[$pid] = (bool)$this->getBackendUser()->isInWebMount($pid); |
||
| 1053 | } |
||
| 1054 | return $this->checkPID_cache[$pid]; |
||
| 1055 | } |
||
| 1056 | |||
| 1057 | /** |
||
| 1058 | * Checks if the position of an updated record is configured to be corrected. This can be disabled globally and changed for elements individually. |
||
| 1059 | * |
||
| 1060 | * @param string $table Table name |
||
| 1061 | * @param int $uid Uid or record |
||
| 1062 | * @return bool TRUE if the position of the record should be updated to match the one in the import structure |
||
| 1063 | */ |
||
| 1064 | public function dontIgnorePid($table, $uid) |
||
| 1067 | } |
||
| 1068 | |||
| 1069 | /** |
||
| 1070 | * Checks if the record exists |
||
| 1071 | * |
||
| 1072 | * @param string $table Table name |
||
| 1073 | * @param int $uid UID of record |
||
| 1074 | * @param string $fields Field list to select. Default is "uid,pid |
||
| 1075 | * @return array Result of \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord() which means the record if found, otherwise FALSE |
||
| 1076 | */ |
||
| 1077 | public function doesRecordExist($table, $uid, $fields = '') |
||
| 1078 | { |
||
| 1079 | return BackendUtility::getRecord($table, $uid, $fields ? $fields : 'uid,pid'); |
||
| 1080 | } |
||
| 1081 | |||
| 1082 | /** |
||
| 1083 | * Returns the page title path of a PID value. Results are cached internally |
||
| 1084 | * |
||
| 1085 | * @param int $pid Record PID to check |
||
| 1086 | * @return string The path for the input PID |
||
| 1087 | */ |
||
| 1088 | public function getRecordPath($pid) |
||
| 1089 | { |
||
| 1090 | if (!isset($this->cache_getRecordPath[$pid])) { |
||
| 1091 | $clause = $this->getBackendUser()->getPagePermsClause(1); |
||
| 1092 | $this->cache_getRecordPath[$pid] = (string)BackendUtility::getRecordPath($pid, $clause, 20); |
||
| 1093 | } |
||
| 1094 | return $this->cache_getRecordPath[$pid]; |
||
| 1095 | } |
||
| 1096 | |||
| 1097 | /** |
||
| 1098 | * Makes a selector-box from optValues |
||
| 1099 | * |
||
| 1100 | * @param string $prefix Form element name |
||
| 1101 | * @param string $value Current value |
||
| 1102 | * @param array $optValues Options to display (key/value pairs) |
||
| 1103 | * @return string HTML select element |
||
| 1104 | */ |
||
| 1105 | public function renderSelectBox($prefix, $value, $optValues) |
||
| 1106 | { |
||
| 1107 | $opt = []; |
||
| 1108 | $isSelFlag = 0; |
||
| 1109 | foreach ($optValues as $k => $v) { |
||
| 1110 | $sel = (string)$k === (string)$value ? ' selected="selected"' : ''; |
||
| 1111 | if ($sel) { |
||
| 1112 | $isSelFlag++; |
||
| 1113 | } |
||
| 1114 | $opt[] = '<option value="' . htmlspecialchars($k) . '"' . $sel . '>' . htmlspecialchars($v) . '</option>'; |
||
| 1115 | } |
||
| 1116 | if (!$isSelFlag && (string)$value !== '') { |
||
| 1117 | $opt[] = '<option value="' . htmlspecialchars($value) . '" selected="selected">' . htmlspecialchars(('[\'' . $value . '\']')) . '</option>'; |
||
| 1118 | } |
||
| 1119 | return '<select name="' . $prefix . '">' . implode('', $opt) . '</select>'; |
||
| 1120 | } |
||
| 1121 | |||
| 1122 | /** |
||
| 1123 | * Compares two records, the current database record and the one from the import memory. |
||
| 1124 | * Will return HTML code to show any differences between them! |
||
| 1125 | * |
||
| 1126 | * @param array $databaseRecord Database record, all fields (new values) |
||
| 1127 | * @param array $importRecord Import memorys record for the same table/uid, all fields (old values) |
||
| 1128 | * @param string $table The table name of the record |
||
| 1129 | * @param bool $inverseDiff Inverse the diff view (switch red/green, needed for pre-update difference view) |
||
| 1130 | * @return string HTML |
||
| 1131 | */ |
||
| 1132 | public function compareRecords($databaseRecord, $importRecord, $table, $inverseDiff = false) |
||
| 1133 | { |
||
| 1134 | // Initialize: |
||
| 1135 | $output = []; |
||
| 1136 | $diffUtility = GeneralUtility::makeInstance(DiffUtility::class); |
||
| 1137 | // Check if both inputs are records: |
||
| 1138 | if (is_array($databaseRecord) && is_array($importRecord)) { |
||
| 1139 | // Traverse based on database record |
||
| 1140 | foreach ($databaseRecord as $fN => $value) { |
||
| 1141 | if (is_array($GLOBALS['TCA'][$table]['columns'][$fN]) && $GLOBALS['TCA'][$table]['columns'][$fN]['config']['type'] !== 'passthrough') { |
||
| 1142 | if (isset($importRecord[$fN])) { |
||
| 1143 | if (trim($databaseRecord[$fN]) !== trim($importRecord[$fN])) { |
||
| 1144 | // Create diff-result: |
||
| 1145 | $output[$fN] = $diffUtility->makeDiffDisplay(BackendUtility::getProcessedValue($table, $fN, !$inverseDiff ? $importRecord[$fN] : $databaseRecord[$fN], 0, 1, 1), BackendUtility::getProcessedValue($table, $fN, !$inverseDiff ? $databaseRecord[$fN] : $importRecord[$fN], 0, 1, 1)); |
||
| 1146 | } |
||
| 1147 | unset($importRecord[$fN]); |
||
| 1148 | } |
||
| 1149 | } |
||
| 1150 | } |
||
| 1151 | // Traverse remaining in import record: |
||
| 1152 | foreach ($importRecord as $fN => $value) { |
||
| 1153 | View Code Duplication | if (is_array($GLOBALS['TCA'][$table]['columns'][$fN]) && $GLOBALS['TCA'][$table]['columns'][$fN]['config']['type'] !== 'passthrough') { |
|
| 1154 | $output[$fN] = '<strong>Field missing</strong> in database'; |
||
| 1155 | } |
||
| 1156 | } |
||
| 1157 | // Create output: |
||
| 1158 | if (!empty($output)) { |
||
| 1159 | $tRows = []; |
||
| 1160 | foreach ($output as $fN => $state) { |
||
| 1161 | $tRows[] = ' |
||
| 1162 | <tr> |
||
| 1163 | <td>' . htmlspecialchars($this->getLanguageService()->sL($GLOBALS['TCA'][$table]['columns'][$fN]['label'])) . ' (' . htmlspecialchars($fN) . ')</td> |
||
| 1164 | <td>' . $state . '</td> |
||
| 1165 | </tr> |
||
| 1166 | '; |
||
| 1167 | } |
||
| 1168 | $output = '<table class="table table-striped table-hover">' . implode('', $tRows) . '</table>'; |
||
| 1169 | } else { |
||
| 1170 | $output = 'Match'; |
||
| 1171 | } |
||
| 1172 | return '<strong class="text-nowrap">[' . htmlspecialchars(($table . ':' . $importRecord['uid'] . ' => ' . $databaseRecord['uid'])) . ']:</strong> ' . $output; |
||
| 1173 | } |
||
| 1174 | return 'ERROR: One of the inputs were not an array!'; |
||
| 1175 | } |
||
| 1176 | |||
| 1177 | /** |
||
| 1178 | * Creates the original file name for a copy-RTE image (magic type) |
||
| 1179 | * |
||
| 1180 | * @param string $string RTE copy filename, eg. "RTEmagicC_user_pm_icon_01.gif.gif |
||
| 1181 | * @return string|null RTE original filename, eg. "RTEmagicP_user_pm_icon_01.gif". If the input filename was NOT prefixed RTEmagicC_ as RTE images would be, NULL is returned! |
||
| 1182 | */ |
||
| 1183 | public function getRTEoriginalFilename($string) |
||
| 1194 | } |
||
| 1195 | |||
| 1196 | /** |
||
| 1197 | * Returns file processing object, initialized only once. |
||
| 1198 | * |
||
| 1199 | * @return ExtendedFileUtility File processor object |
||
| 1200 | */ |
||
| 1201 | public function getFileProcObj() |
||
| 1202 | { |
||
| 1203 | if ($this->fileProcObj === null) { |
||
| 1204 | $this->fileProcObj = GeneralUtility::makeInstance(ExtendedFileUtility::class); |
||
| 1205 | $this->fileProcObj->setActionPermissions(); |
||
| 1206 | } |
||
| 1207 | return $this->fileProcObj; |
||
| 1208 | } |
||
| 1209 | |||
| 1210 | /** |
||
| 1211 | * Call Hook |
||
| 1212 | * |
||
| 1213 | * @param string $name Name of the hook |
||
| 1214 | * @param array $params Array with params |
||
| 1215 | */ |
||
| 1216 | public function callHook($name, $params) |
||
| 1220 | } |
||
| 1221 | } |
||
| 1222 | |||
| 1223 | /** |
||
| 1224 | * Set flag to control whether disabled records and their children are excluded (true) or included (false). Defaults |
||
| 1225 | * to the old behaviour of including everything. |
||
| 1226 | * |
||
| 1227 | * @param bool $excludeDisabledRecords Set to true if if all disabled records should be excluded, false otherwise |
||
| 1228 | * @return \TYPO3\CMS\Impexp\ImportExport $this for fluent calls |
||
| 1229 | */ |
||
| 1230 | public function setExcludeDisabledRecords($excludeDisabledRecords = false) |
||
| 1231 | { |
||
| 1232 | $this->excludeDisabledRecords = $excludeDisabledRecords; |
||
| 1233 | return $this; |
||
| 1234 | } |
||
| 1235 | |||
| 1236 | /***************************** |
||
| 1237 | * Error handling |
||
| 1238 | *****************************/ |
||
| 1239 | |||
| 1240 | /** |
||
| 1241 | * Sets error message in the internal error log |
||
| 1242 | * |
||
| 1243 | * @param string $msg Error message |
||
| 1244 | */ |
||
| 1245 | public function error($msg) |
||
| 1246 | { |
||
| 1247 | $this->errorLog[] = $msg; |
||
| 1248 | } |
||
| 1249 | |||
| 1250 | /** |
||
| 1251 | * Returns a table with the error-messages. |
||
| 1252 | * |
||
| 1253 | * @return string HTML print of error log |
||
| 1254 | */ |
||
| 1255 | public function printErrorLog() |
||
| 1256 | { |
||
| 1257 | return !empty($this->errorLog) ? DebugUtility::viewArray($this->errorLog) : ''; |
||
| 1258 | } |
||
| 1259 | |||
| 1260 | /** |
||
| 1261 | * @return BackendUserAuthentication |
||
| 1262 | */ |
||
| 1263 | protected function getBackendUser() |
||
| 1264 | { |
||
| 1265 | return $GLOBALS['BE_USER']; |
||
| 1266 | } |
||
| 1267 | |||
| 1268 | /** |
||
| 1269 | * @return LanguageService |
||
| 1270 | */ |
||
| 1271 | protected function getLanguageService() |
||
| 1274 | } |
||
| 1275 | } |
||
| 1276 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.