BUGFIX-17354-fallback-for-menus-content_fallback-7_6-.patch

Nikolaj Wojtkowiak-Pfänder, 2016-11-18 09:23

Download (37.9 KB)

View differences:

typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
838 838
            ) {
839 839
                if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], [-1, 0])) {
840 840
                    $overlayMode = $querySettings->getLanguageMode() === 'strict' ? 'hideNonTranslated' : '';
841
                    $row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
841
					$row = $pageRepository->getRecordOverlayWithFallback(
842
						$tableName, $row, $querySettings->getLanguageUid(), $overlayMode
843
					);
842 844
                }
843 845
            }
844 846
            if ($row !== null && is_array($row)) {
typo3/sysext/frontend/Classes/Aspect/FileMetadataOverlayAspect.php
36 36
    {
37 37
        $overlaidMetaData = $data->getArrayCopy();
38 38
        $this->getTsfe()->sys_page->versionOL('sys_file_metadata', $overlaidMetaData);
39
        $overlaidMetaData = $this->getTsfe()->sys_page->getRecordOverlay(
40
            'sys_file_metadata',
41
            $overlaidMetaData,
42
            $this->getTsfe()->sys_language_content,
43
            $this->getTsfe()->sys_language_contentOL
44
        );
39
		$overlaidMetaData = $this->getTsfe()->sys_page->getRecordOverlayWithFallback(
40
			'sys_file_metadata',
41
			$overlaidMetaData
42
		);
45 43
        if ($overlaidMetaData !== null) {
46 44
            $data->exchangeArray($overlaidMetaData);
47 45
        }
typo3/sysext/frontend/Classes/Category/Collection/CategoryCollection.php
138 138
                    if ($this->getItemTableName() === 'pages') {
139 139
                        $record = $tsfe->sys_page->getPageOverlay($record);
140 140
                    } else {
141
                        $record = $tsfe->sys_page->getRecordOverlay(
142
                            $this->getItemTableName(),
143
                            $record,
144
                            $tsfe->sys_language_content,
145
                            $tsfe->sys_language_contentOL
146
                        );
141
						$record = $this->getFrontendObject()->sys_page->getRecordOverlayWithFallback(
142
							$this->getItemTableName(),
143
							$record
144
						);
147 145
                    }
148 146
                }
149 147
                // Record may have been unset during the overlay process
typo3/sysext/frontend/Classes/ContentObject/FilesContentObject.php
189 189
            if ($referencesForeignTable === 'pages') {
190 190
                $element = $pageRepository->getPageOverlay($element);
191 191
            } else {
192
                $element = $pageRepository->getRecordOverlay(
193
                    $referencesForeignTable,
194
                    $element,
195
                    $GLOBALS['TSFE']->sys_language_content,
196
                    $GLOBALS['TSFE']->sys_language_contentOL
197
                );
192
				$element = $pageRepository->getRecordOverlayWithFallback($referencesForeignTable, $element);
198 193
            }
199 194
        }
200 195

  
typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
1246 1246
                $tok = true;
1247 1247
                // There is an alternative language active AND the current page requires a translation:
1248 1248
                if ($tsfe->sys_language_uid && GeneralUtility::hideIfNotTranslated($data['l18n_cfg'])) {
1249
                    if (!$data['_PAGES_OVERLAY']) {
1249
					if (!$data['_PAGES_OVERLAY'] || (int)$data['sys_language_uid'] !== (int)$GLOBALS['TSFE']->sys_language_uid) {
1250 1250
                        $tok = false;
1251 1251
                    }
1252 1252
                }
......
2160 2160
        while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($resource)) {
2161 2161
            $this->sys_page->versionOL('tt_content', $row);
2162 2162
            if ($tsfe->sys_language_contentOL && $basePageRow['_PAGES_OVERLAY_LANGUAGE']) {
2163
                $row = $this->sys_page->getRecordOverlay('tt_content', $row, $basePageRow['_PAGES_OVERLAY_LANGUAGE'], $tsfe->sys_language_contentOL);
2163
				$row = $this->sys_page->getRecordOverlayWithFallback('tt_content', $row, $basePageRow['_PAGES_OVERLAY_LANGUAGE']);
2164 2164
            }
2165 2165
            if ($this->mconf['sectionIndex.']['type'] !== 'all') {
2166 2166
                $doIncludeInSectionIndex = $row['sectionIndex'] >= 1;
typo3/sysext/frontend/Classes/ContentObject/RecordsContentObject.php
49 49
        $this->itemArray = [];
50 50
        $this->data = [];
51 51

  
52
		$tsfe = $this->getTypoScriptFrontendController();
53

  
52 54
        $theValue = '';
53
        $originalRec = $GLOBALS['TSFE']->currentRecord;
55
		$originalRec = $tsfe->currentRecord;
54 56
        // If the currentRecord is set, we register, that this record has invoked this function.
55 57
        // It's should not be allowed to do this again then!!
56 58
        if ($originalRec) {
57
            ++$GLOBALS['TSFE']->recordRegister[$originalRec];
59
			++$tsfe->recordRegister[$originalRec];
58 60
        }
59 61

  
60 62
        $tables = isset($conf['tables.']) ? $this->cObj->stdWrap($conf['tables'], $conf['tables.']) : $conf['tables'];
......
89 91
                foreach ($this->itemArray as $val) {
90 92
                    $row = $this->data[$val['table']][$val['id']];
91 93
                    // Perform overlays if necessary (records coming from category collections are already overlaid)
92
                    if ($source) {
93
                        // Versioning preview
94
                        $GLOBALS['TSFE']->sys_page->versionOL($val['table'], $row);
95
                        // Language overlay
96
                        if (is_array($row) && $GLOBALS['TSFE']->sys_language_contentOL) {
97
                            if ($val['table'] === 'pages') {
98
                                $row = $GLOBALS['TSFE']->sys_page->getPageOverlay($row);
99
                            } else {
100
                                $row = $GLOBALS['TSFE']->sys_page->getRecordOverlay($val['table'], $row, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
101
                            }
102
                        }
103
                    }
94
					if ($source) {
95
						// Versioning preview
96
						$tsfe->sys_page->versionOL($val['table'], $row);
97
						// Language overlay
98
						if (is_array($row) && $tsfe->sys_language_contentOL) {
99
							if ($val['table'] === 'pages') {
100
								$row = $tsfe->sys_page->getPageOverlay($row);
101
							} else {
102
								$fallbackChain = NULL;
103
								if (isset($conf['languageFallbackChain'])) {
104
									$fallbackChain = GeneralUtility::intExplode(',', $conf['languageFallbackChain']);
105
								}
106

  
107
								$pageLanguageBinding = !isset($conf['respectPageLanguageBinding']) || (int)$conf['respectPageLanguageBinding'] !== '0';
108

  
109
								$row = $tsfe->sys_page->getRecordOverlayWithFallback(
110
									$val['table'], $row, NULL, NULL, $fallbackChain, $pageLanguageBinding
111
								);
112
							}
113
						}
114
					}
104 115
                    // Might be unset during the overlay process
105 116
                    if (is_array($row)) {
106 117
                        $dontCheckPid = isset($conf['dontCheckPid.']) ? $this->cObj->stdWrap($conf['dontCheckPid'], $conf['dontCheckPid.']) : $conf['dontCheckPid'];
107 118
                        if (!$dontCheckPid) {
108 119
                            $row = $this->cObj->checkPid($row['pid']) ? $row : '';
109 120
                        }
110
                        if ($row && !$GLOBALS['TSFE']->recordRegister[$val['table'] . ':' . $val['id']]) {
121
						if ($row && !$tsfe->recordRegister[($val['table'] . ':' . $val['id'])]) {
111 122
                            $renderObjName = $conf['conf.'][$val['table']] ?: '<' . $val['table'];
112 123
                            $renderObjKey = $conf['conf.'][$val['table']] ? 'conf.' . $val['table'] : '';
113 124
                            $renderObjConf = $conf['conf.'][$val['table'] . '.'];
114 125
                            $this->cObj->currentRecordNumber++;
115 126
                            $cObj->parentRecordNumber = $this->cObj->currentRecordNumber;
116
                            $GLOBALS['TSFE']->currentRecord = $val['table'] . ':' . $val['id'];
127
							$tsfe->currentRecord = $val['table'] . ':' . $val['id'];
117 128
                            $this->cObj->lastChanged($row['tstamp']);
118 129
                            $cObj->start($row, $val['table']);
119 130
                            $tmpValue = $cObj->cObjGetSingle($renderObjName, $renderObjConf, $renderObjKey);
......
131 142
            $theValue = $this->cObj->stdWrap($theValue, $conf['stdWrap.']);
132 143
        }
133 144
        // Restore
134
        $GLOBALS['TSFE']->currentRecord = $originalRec;
145
		$tsfe->currentRecord = $originalRec;
135 146
        if ($originalRec) {
136 147
            --$GLOBALS['TSFE']->recordRegister[$originalRec];
137 148
        }
......
233 244
    {
234 245
        return $GLOBALS['TT'];
235 246
    }
247

  
248
	/**
249
	 * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
250
	 */
251
	protected function getTypoScriptFrontendController() {
252
		return $GLOBALS['TSFE'];
253
	}
236 254
}
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
604 604
     */
605 605
    public $sys_language_content = 0;
606 606

  
607
	/**
608
	 * Contains the prioritized language fallback chain
609
	 *
610
	 * @var array
611
	 */
612
	public $languageFallbackChain = array();
613

  
614
	/**
615
	 * Contains the prioritized language fallback chain for the current page
616
	 *
617
	 * @var array
618
	 */
619
	public $languageFallbackChainWithPageLanguageBinding = array();
620

  
607 621
    /**
608 622
     * Site content overlay flag; If set - and sys_language_content is > 0 - ,
609 623
     * records selected will try to look for a translation pointing to their uid. (If
......
2694 2708
        // Get values from TypoScript:
2695 2709
        $this->sys_language_uid = ($this->sys_language_content = (int)$this->config['config']['sys_language_uid']);
2696 2710
        list($this->sys_language_mode, $sys_language_content) = GeneralUtility::trimExplode(';', $this->config['config']['sys_language_mode']);
2697
        $this->sys_language_contentOL = $this->config['config']['sys_language_overlay'];
2711
		$languageFallbackChain = GeneralUtility::intExplode(',', $this->config['config']['languageFallbackChain']);
2712
		$this->sys_language_contentOL = $this->config['config']['sys_language_overlay'];
2698 2713
        // If sys_language_uid is set to another language than default:
2699 2714
        if ($this->sys_language_uid > 0) {
2700 2715
            // check whether a shortcut is overwritten by a translated page
......
2715 2730
                                $this->pageNotFoundAndExit('Page is not available in the requested language (strict).');
2716 2731
                                break;
2717 2732
                            case 'content_fallback':
2718
                                $fallBackOrder = GeneralUtility::intExplode(',', $sys_language_content);
2719
                                foreach ($fallBackOrder as $orderValue) {
2720
                                    if ((string)$orderValue === '0' || !empty($this->sys_page->getPageOverlay($this->id, $orderValue))) {
2721
                                        $this->sys_language_content = $orderValue;
2722
                                        // Setting content uid (but leaving the sys_language_uid)
2723
                                        break;
2724
                                    }
2725
                                }
2733
								// default is to fallback to default language
2734
								$this->sys_language_content = 0;
2735

  
2736
								foreach ($languageFallbackChain as $languageId) {
2737
									// break the language chain if the current language is selected
2738
									if ($languageId === 0) {
2739
										break;
2740
									}
2741

  
2742
									// ignore current and invalid language ids
2743
									if ($this->sys_language_uid === $languageId || $languageId < 0) {
2744
										continue;
2745
									}
2746

  
2747
									$pageOverlay = $this->sys_page->getPageOverlay($this->id, $languageId);
2748
									if (!empty($pageOverlay)) {
2749
										// Setting content uid (but leaving the sys_language_uid)
2750
										$this->sys_language_content = $languageId;
2751
										// overlay page with existing page overlay
2752
										$this->page = array_merge($this->page, $pageOverlay);
2753

  
2754
										break;
2755
									}
2756
								}
2726 2757
                                break;
2727 2758
                            case 'ignore':
2728 2759
                                $this->sys_language_content = $this->sys_language_uid;
......
2730 2761
                            default:
2731 2762
                                // Default is that everything defaults to the default language...
2732 2763
                                $this->sys_language_uid = ($this->sys_language_content = 0);
2764
								break;
2733 2765
                        }
2734 2766
                    }
2735 2767
                }
2736 2768
            } else {
2737
                // Setting sys_language if an overlay record was found (which it is only if a language is used)
2738
                $this->page = $this->sys_page->getPageOverlay($this->page, $this->sys_language_uid);
2769
				// overlay page with existing page overlay
2770
				$this->page = array_merge($this->page, $olRec);
2739 2771
            }
2772

  
2773
			// calculate the language fallback chains
2774
			if ($this->sys_language_mode === 'content_fallback') {
2775
				foreach ($languageFallbackChain as $languageId) {
2776
					// ignore current and invalid language ids
2777
					if ($this->sys_language_uid === $languageId || $languageId < 0) {
2778
						continue;
2779
					}
2780

  
2781
					$this->languageFallbackChain[] = $languageId;
2782
					if ($languageId === 0 || count($this->sys_page->getPageOverlay($this->id, $languageId))) {
2783
						$this->languageFallbackChainWithPageLanguageBinding[] = $languageId;
2784
					}
2785
				}
2786
			}
2740 2787
        }
2741 2788
        // Setting sys_language_uid inside sys-page:
2742 2789
        $this->sys_page->sys_language_uid = $this->sys_language_uid;
2743
        // If default translation is not available:
2744
        if ((!$this->sys_language_uid || !$this->sys_language_content) && GeneralUtility::hideIfDefaultLanguage($this->page['l18n_cfg'])) {
2745
            $message = 'Page is not available in default language.';
2790
		// If default translation is not to be selected
2791
		if ($this->page['l18n_cfg']&1 && !($this->sys_language_uid && $this->sys_language_content)) {
2792
			$message = 'Page is not available in default language.';
2746 2793
            GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
2747 2794
            $this->pageNotFoundAndExit($message);
2748 2795
        }
typo3/sysext/frontend/Classes/Page/PageRepository.php
22 22
use TYPO3\CMS\Core\Utility\HttpUtility;
23 23
use TYPO3\CMS\Core\Utility\RootlineUtility;
24 24
use TYPO3\CMS\Core\Versioning\VersionState;
25
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
25 26

  
26 27
/**
27 28
 * Page functions, a lot of sql/pages-related functions
......
355 356
            return [];
356 357
        }
357 358
        // Initialize:
358
        if ($lUid < 0) {
359
            $lUid = $this->sys_language_uid;
360
        }
359
		$noSpecialLanguageRequested = FALSE;
360
		if ($lUid < 0) {
361
			$noSpecialLanguageRequested = TRUE;
362
			$lUid = $this->sys_language_uid;
363
		}
364

  
361 365
        $row = null;
362 366
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'])) {
363 367
            foreach ($pagesInput as &$origPage) {
......
371 375
            }
372 376
            unset($origPage);
373 377
        }
378

  
374 379
        // If language UID is different from zero, do overlay:
375 380
        if ($lUid) {
376 381
            $fieldArr = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'], true);
......
390 395
                    $page_ids[] = $origPage;
391 396
                }
392 397
            }
393
            if (!empty($fieldArr)) {
394
                if (!in_array('pid', $fieldArr, true)) {
395
                    $fieldArr[] = 'pid';
396
                }
397
                // NOTE to enabledFields('pages_language_overlay'):
398
                // Currently the showHiddenRecords of TSFE set will allow
399
                // pages_language_overlay records to be selected as they are
400
                // child-records of a page.
401
                // However you may argue that the showHiddenField flag should
402
                // determine this. But that's not how it's done right now.
403
                // Selecting overlay record:
404
                $db = $this->getDatabaseConnection();
405
                $res = $db->exec_SELECTquery(
406
                    implode(',', $fieldArr),
407
                    'pages_language_overlay',
408
                    'pid IN(' . implode(',', $db->cleanIntArray($page_ids)) . ')'
409
                    . ' AND sys_language_uid=' . (int)$lUid . $this->enableFields('pages_language_overlay')
410
                );
411
                $overlays = [];
412
                while ($row = $db->sql_fetch_assoc($res)) {
413
                    $this->versionOL('pages_language_overlay', $row);
414
                    if (is_array($row)) {
415
                        $row['_PAGES_OVERLAY'] = true;
416
                        $row['_PAGES_OVERLAY_UID'] = $row['uid'];
417
                        $row['_PAGES_OVERLAY_LANGUAGE'] = $lUid;
418
                        $origUid = $row['pid'];
419
                        // Unset vital fields that are NOT allowed to be overlaid:
420
                        unset($row['uid']);
421
                        unset($row['pid']);
422
                        $overlays[$origUid] = $row;
423
                    }
424
                }
425
                $db->sql_free_result($res);
426
            }
398

  
399
			if (!empty($fieldArr)) {
400
				if (!in_array('pid', $fieldArr, TRUE)) {
401
					$fieldArr[] = 'pid';
402
				}
403
				$languageClause = 'sys_language_uid=' . (int)$lUid . ' ';
404

  
405
				$languageList = array();
406
				if ($noSpecialLanguageRequested) {
407
					$languageList = array_unique(array_merge(
408
						[ $lUid ],
409
						$this->getTypoScriptFrontendController()->languageFallbackChain,
410
						[ $this->getTypoScriptFrontendController()->sys_language_content ]
411
					));
412

  
413
					$languageIds = implode(',', array_map('intval', $languageList));
414
					$languageClause = 'sys_language_uid IN (' . $languageIds . ') ';
415
				}
416
				// NOTE to enabledFields('pages_language_overlay'):
417
				// Currently the showHiddenRecords of TSFE set will allow pages_language_overlay records to be selected as they are child-records of a page.
418
				// However you may argue that the showHiddenField flag should determine this. But that's not how it's done right now.
419
				// Selecting overlay record:
420
				if (!in_array('sys_language_uid', $fieldArr)) {
421
					$fieldArr[] = 'sys_language_uid';
422
				}
423
				$db = $this->getDatabaseConnection();
424
				$res = $db->exec_SELECTquery(
425
					implode(',', $fieldArr),
426
					'pages_language_overlay',
427
					'pid IN(' . implode(',', $db->cleanIntArray($page_ids)) . ')'
428
					. ' AND ' . $languageClause . $this->enableFields('pages_language_overlay')
429
				);
430

  
431
				$overlays = array();
432
				while ($row = $db->sql_fetch_assoc($res)) {
433
					$this->versionOL('pages_language_overlay', $row);
434

  
435
					if (is_array($row)) {
436
						$row['_PAGES_OVERLAY'] = TRUE;
437
						$row['_PAGES_OVERLAY_UID'] = $row['uid'];
438
						$row['_PAGES_OVERLAY_LANGUAGE'] = $lUid;
439
						$origUid = $row['pid'];
440
						// Unset vital fields that are NOT allowed to be overlaid:
441
						unset($row['uid']);
442
						unset($row['pid']);
443
						$overlays[$origUid] = $row;
444
					}
445
				}
446
				$db->sql_free_result($res);
447
			}
427 448
        }
428 449
        // Create output:
429 450
        $pagesOutput = [];
......
446 467
                }
447 468
            }
448 469
        }
470

  
449 471
        return $pagesOutput;
450 472
    }
451 473

  
474
	/**
475
	 * Creates a language overlay for records stored inside tables which contain the
476
	 * translation information themselves. In addition to getRecordOverlay this method
477
	 * also checks for specified content language fallbacks and includes them.
478
	 *
479
	 * @param string $table Table name
480
	 * @param array $row Record to overlay. Must containt uid, pid and $table]['ctrl']['languageField']
481
	 * @param int $sys_language_content Pointer to the sys_language uid for content on the site.
482
	 * @param string $OLmode Overlay mode. If "hideNonTranslated" then records without translation will not be returned  un-translated but unset (and return value is FALSE)
483
	 * @param array|NULL $fallbackList ordered fallback list of language ids
484
	 * @param bool $pageLanguageBinding use page language binding for the language fallback chain (only used if fallbackList is NULL)
485
	 * @return mixed Returns the input record, possibly overlaid with a translation. But if $OLmode is "hideNonTranslated" then it will return NULL if no translation is found.
486
	 * @throws \UnexpectedValueException
487
	 */
488
	public function getRecordOverlayWithFallback($table, $row, $sys_language_content = NULL, $OLmode = NULL, $fallbackList = NULL, $pageLanguageBinding = TRUE) {
489
		$tsfe = $this->getTypoScriptFrontendController();
490
		$sys_language_content = $sys_language_content !== NULL ? $sys_language_content : $tsfe->sys_language_content;
491
		$OLmode = $OLmode !== NULL ? $OLmode: $tsfe->sys_language_contentOL;
492
		if ($fallbackList === NULL) {
493
			$fallbackList = $tsfe->languageFallbackChainWithPageLanguageBinding;
494
			if (!$pageLanguageBinding) {
495
				$fallbackList = $tsfe->languageFallbackChain;
496
			}
497
		}
498

  
499
		$record = $this->getRecordOverlayWithoutFallback($table, $row, $sys_language_content, $OLmode);
500
		if (!is_array($record) || !isset($record['_LOCALIZED_UID'])) {
501
			if ($sys_language_content && $OLmode !== 'hideNonTranslated' && !empty($fallbackList)) {
502
				foreach ($fallbackList as $fallbackId) {
503
					$fallbackId = (int)$fallbackId;
504
					if ($fallbackId === 0) {
505
						$record = $row;
506
						break;
507
					}
508

  
509
					$record = $this->getRecordOverlayWithoutFallback($table, $row, $fallbackId, $OLmode);
510
					if (isset($record['_LOCALIZED_UID']) && is_array($record)) {
511
						break;
512
					}
513
				}
514
			}
515
		}
516
		return $record;
517
	}
518

  
452 519
    /**
453 520
     * Creates language-overlay for records in general (where translation is found
454 521
     * in records from the same table)
......
460 527
     * @throws \UnexpectedValueException
461 528
     * @return mixed Returns the input record, possibly overlaid with a translation.  But if $OLmode is "hideNonTranslated" then it will return FALSE if no translation is found.
462 529
     */
463
    public function getRecordOverlay($table, $row, $sys_language_content, $OLmode = '')
464
    {
465
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
466
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
467
                $hookObject = GeneralUtility::getUserObj($classRef);
468
                if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
469
                    throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881658);
470
                }
471
                $hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
472
            }
473
        }
474
        if ($row['uid'] > 0 && ($row['pid'] > 0 || in_array($table, $this->tableNamesAllowedOnRootLevel, true))) {
475
            if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
476
                // Return record for ALL languages untouched
477
                // TODO: Fix call stack to prevent this situation in the first place
478
                if (!$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'] && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] !== -1) {
479
                    // Will not be able to work with other tables (Just didn't implement it yet;
480
                    // Requires a scan over all tables [ctrl] part for first FIND the table that
481
                    // carries localization information for this table (which could even be more
482
                    // than a single table) and then use that. Could be implemented, but obviously
483
                    // takes a little more....) Will try to overlay a record only if the
484
                    // sys_language_content value is larger than zero.
485
                    if ($sys_language_content > 0) {
486
                        // Must be default language, otherwise no overlaying
487
                        if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) {
488
                            // Select overlay record:
489
                            $res = $this->getDatabaseConnection()->exec_SELECTquery('*', $table, 'pid=' . (int)$row['pid'] . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . (int)$sys_language_content . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$row['uid'] . $this->enableFields($table), '', '', '1');
490
                            $olrow = $this->getDatabaseConnection()->sql_fetch_assoc($res);
491
                            $this->getDatabaseConnection()->sql_free_result($res);
492
                            $this->versionOL($table, $olrow);
493
                            // Merge record content by traversing all fields:
494
                            if (is_array($olrow)) {
495
                                if (isset($olrow['_ORIG_uid'])) {
496
                                    $row['_ORIG_uid'] = $olrow['_ORIG_uid'];
497
                                }
498
                                if (isset($olrow['_ORIG_pid'])) {
499
                                    $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
500
                                }
501
                                foreach ($row as $fN => $fV) {
502
                                    if ($fN !== 'uid' && $fN !== 'pid' && isset($olrow[$fN])) {
503
                                        if ($this->shouldFieldBeOverlaid($table, $fN, $olrow[$fN])) {
504
                                            $row[$fN] = $olrow[$fN];
505
                                        }
506
                                    } elseif ($fN === 'uid') {
507
                                        $row['_LOCALIZED_UID'] = $olrow['uid'];
508
                                    }
509
                                }
510
                            } elseif ($OLmode === 'hideNonTranslated' && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) {
511
                                // Unset, if non-translated records should be hidden. ONLY done if the source
512
                                // record really is default language and not [All] in which case it is allowed.
513
                                unset($row);
514
                            }
515
                        } elseif ($sys_language_content != $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]) {
516
                            unset($row);
517
                        }
518
                    } else {
519
                        // When default language is displayed, we never want to return a record carrying
520
                        // another language!
521
                        if ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
522
                            unset($row);
523
                        }
524
                    }
525
                }
526
            }
527
        }
528
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
529
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
530
                $hookObject = GeneralUtility::getUserObj($classRef);
531
                if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
532
                    throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881659);
533
                }
534
                $hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
535
            }
536
        }
537
        return $row;
538
    }
530
	public function getRecordOverlay($table, $row, $sys_language_content, $OLmode = '') {
531
		GeneralUtility::logDeprecatedFunction();
532
		return $this->getRecordOverlayWithoutFallback($table, $row, $sys_language_content, $OLmode);
533
	}
534

  
535
	/**
536
	 * Creates a language overlay for records stored inside tables which contain the
537
	 * translation information themselves.
538
	 *
539
	 *
540
	 * @param string $table Table name the record comes from
541
	 * @param array $row Record to overlay. Must contain the columns uid, pid and $TCA[$table]['ctrl']['languageField']
542
	 * @param int $sys_language_content Pointer to the sys_language uid to use for content.
543
	 * @param string $OLmode Overlay mode. If "hideNonTranslated" then records without translation will not be returned translated but unset (and return value is FALSE)
544
	 * @throws \InvalidArgumentException
545
	 * @throws \UnexpectedValueException
546
	 * @return mixed Returns the input record, possibly overlaid with a translation. But if $OLmode is "hideNonTranslated" then it will return NULL if no translation is found.
547
	 */
548
	public function getRecordOverlayWithoutFallback($table, $row, $sys_language_content, $OLmode) {
549
		if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
550
			foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
551
				$hookObject = GeneralUtility::getUserObj($classRef);
552
				if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
553
					throw new \UnexpectedValueException('$hookObject must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881658);
554
				}
555
				$hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
556
			}
557
		}
558
		if ($row['uid'] > 0 && ($row['pid'] > 0 || in_array($table, $this->tableNamesAllowedOnRootLevel, TRUE))) {
559
			if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
560
				if (!$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) {
561
					// Will not be able to work with other tables (Just didn't implement it yet;
562
					// Requires a scan over all tables [ctrl] part for first FIND the table that
563
					// carries localization information for this table (which could even be more
564
					// than a single table) and then use that. Could be implemented, but obviously
565
					// takes a little more....) Will try to overlay a record only if the
566
					// sys_language_content value is larger than zero.
567
					if ($sys_language_content > 0) {
568
						// Must be default language or [All], otherwise no overlaying:
569
						if ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0) {
570
							// Select overlay record:
571
							$res = $this->getDatabaseConnection()->exec_SELECTquery('*', $table, 'pid=' . (int)$row['pid'] . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . (int)$sys_language_content . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$row['uid'] . $this->enableFields($table), '', '', '1');
572
							$olrow = $this->getDatabaseConnection()->sql_fetch_assoc($res);
573
							$this->getDatabaseConnection()->sql_free_result($res);
574
							$this->versionOL($table, $olrow);
575
							// Merge record content by traversing all fields:
576
							if (is_array($olrow)) {
577
								if (isset($olrow['_ORIG_uid'])) {
578
									$row['_ORIG_uid'] = $olrow['_ORIG_uid'];
579
								}
580
								if (isset($olrow['_ORIG_pid'])) {
581
									$row['_ORIG_pid'] = $olrow['_ORIG_pid'];
582
								}
583
								foreach ($row as $fN => $fV) {
584
									if ($fN !== 'uid' && $fN !== 'pid' && isset($olrow[$fN])) {
585
										if ($this->shouldFieldBeOverlaid($table, $fN, $olrow[$fN])) {
586
											$row[$fN] = $olrow[$fN];
587
										}
588
									} elseif ($fN === 'uid') {
589
										$row['_LOCALIZED_UID'] = $olrow['uid'];
590
									}
591
								}
592
							} elseif ($OLmode === 'hideNonTranslated' && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) {
593
								// Unset, if non-translated records should be hidden. ONLY done if the source
594
								// record really is default language and not [All] in which case it is allowed.
595
								$row = NULL;
596
							}
597
						} elseif ($sys_language_content != $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]) {
598
							$row = NULL;
599
						}
600
					} else {
601
						// When default language is displayed, we never want to return a record carrying
602
						// another language!
603
						if ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
604
							$row = NULL;
605
						}
606
					}
607
				}
608
			}
609
		}
610
		if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
611
			foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
612
				$hookObject = GeneralUtility::getUserObj($classRef);
613
				if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
614
					throw new \UnexpectedValueException('$hookObject must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881659);
615
				}
616
				$hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
617
			}
618
		}
619

  
620
		return $row;
621
	}
539 622

  
540 623
    /************************************************
541 624
     *
typo3/sysext/frontend/Tests/Unit/ContentObject/Menu/AbstractMenuContentObjectTest.php
98 98
        $this->subject->sys_page->expects($this->once())->method('getPage')->will($this->returnValue(['_PAGES_OVERLAY_LANGUAGE' => 1]));
99 99
        $this->subject->parent_cObj->expects($this->once())->method('exec_getQuery')->will($this->returnValue(1));
100 100
        $GLOBALS['TYPO3_DB']->expects($this->exactly(2))->method('sql_fetch_assoc')->will($this->onConsecutiveCalls($this->returnValue(['uid' => 0, 'header' => 'NOT_OVERLAID']), $this->returnValue(false)));
101
        $this->subject->sys_page->expects($this->once())->method('getRecordOverlay')->will($this->returnValue(['uid' => 0, 'header' => 'OVERLAID']));
102
        $result = $this->subject->_call('sectionIndex', 'field');
101
		$this->subject->sys_page->expects($this->once())->method('getRecordOverlayWithFallback')->will($this->returnValue(array('uid' => 0, 'header' => 'OVERLAID')));
102
		$result = $this->subject->_call('sectionIndex', 'field');
103 103
        $this->assertEquals($result[0]['title'], 'OVERLAID');
104 104
    }
105 105

  
106
-