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.