21
21
use Psr \Http \Message \ServerRequestInterface ;
22
22
use Psr \Http \Server \MiddlewareInterface ;
23
23
use Psr \Http \Server \RequestHandlerInterface ;
24
+ use TYPO3 \CMS \Core \Cache \CacheManager ;
24
25
use TYPO3 \CMS \Core \Context \Context ;
25
26
use TYPO3 \CMS \Core \Context \DateTimeAspect ;
26
27
use TYPO3 \CMS \Core \Context \LanguageAspectFactory ;
27
28
use TYPO3 \CMS \Core \Context \VisibilityAspect ;
28
29
use TYPO3 \CMS \Core \Domain \Repository \PageRepository ;
29
30
use TYPO3 \CMS \Core \Routing \PageArguments ;
30
31
use TYPO3 \CMS \Core \Utility \GeneralUtility ;
32
+ use TYPO3 \CMS \Core \Utility \RootlineUtility ;
31
33
use TYPO3 \CMS \Frontend \Aspect \PreviewAspect ;
32
34
use TYPO3 \CMS \Frontend \Controller \ErrorController ;
33
35
use TYPO3 \CMS \Frontend \Page \PageAccessFailureReasons ;
@@ -66,19 +68,20 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
66
68
}
67
69
// The preview flag is set if the current page turns out to be hidden
68
70
$ showHiddenPages = $ this ->checkIfPageIsHidden ($ pageArguments ->getPageId (), $ request );
71
+ $ rootlineRequiresPreviewFlag = $ this ->checkIfRootlineRequiresPreview ($ pageArguments ->getPageId ());
69
72
$ simulatingDate = $ this ->simulateDate ($ request );
70
73
$ simulatingGroup = $ this ->simulateUserGroup ($ request );
71
74
$ showHiddenRecords = $ visibilityAspect ->includeHidden ();
72
75
$ isOfflineWorkspace = $ this ->context ->getPropertyFromAspect ('workspace ' , 'id ' , 0 ) > 0 ;
73
- $ isPreview = $ simulatingDate || $ simulatingGroup || $ showHiddenRecords || $ showHiddenPages || $ isOfflineWorkspace ;
76
+ $ isPreview = $ simulatingDate || $ simulatingGroup || $ showHiddenRecords || $ showHiddenPages || $ isOfflineWorkspace || $ rootlineRequiresPreviewFlag ;
74
77
if ($ this ->context ->hasAspect ('frontend.preview ' )) {
75
78
$ previewAspect = $ this ->context ->getAspect ('frontend.preview ' );
76
79
$ isPreview = $ previewAspect ->isPreview () || $ isPreview ;
77
80
}
78
81
$ previewAspect = GeneralUtility::makeInstance (PreviewAspect::class, $ isPreview );
79
82
$ this ->context ->setAspect ('frontend.preview ' , $ previewAspect );
80
83
81
- if ($ showHiddenPages ) {
84
+ if ($ showHiddenPages || $ rootlineRequiresPreviewFlag ) {
82
85
$ newAspect = GeneralUtility::makeInstance (VisibilityAspect::class, true , $ visibilityAspect ->includeHiddenContent (), $ visibilityAspect ->includeDeletedRecords ());
83
86
$ this ->context ->setAspect ('visibility ' , $ newAspect );
84
87
}
@@ -87,6 +90,46 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
87
90
return $ handler ->handle ($ request );
88
91
}
89
92
93
+ protected function checkIfRootlineRequiresPreview (int $ pageId ): bool
94
+ {
95
+ $ rootlineUtility = GeneralUtility::makeInstance (RootlineUtility::class, $ pageId , '' , $ this ->context );
96
+ $ pageRepository = GeneralUtility::makeInstance (PageRepository::class, $ this ->context );
97
+ $ groupRestricted = false ;
98
+ $ timeRestricted = false ;
99
+ $ hidden = false ;
100
+ try {
101
+ $ rootLine = $ rootlineUtility ->get ();
102
+ $ pageInfo = $ pageRepository ->getPage_noCheck ($ pageId );
103
+ // Only check rootline if the current page has not set extendToSubpages itself
104
+ // @see \TYPO3\CMS\Backend\Routing\PreviewUriBuilder::class
105
+ if (!(bool )($ pageInfo ['extendToSubpages ' ] ?? false )) {
106
+ // remove the current page from the rootline
107
+ array_shift ($ rootLine );
108
+ foreach ($ rootLine as $ page ) {
109
+ // Skip root node and pages which do not define extendToSubpages
110
+ if ((int )($ page ['uid ' ] ?? 0 ) === 0 || !(bool )($ page ['extendToSubpages ' ] ?? false )) {
111
+ continue ;
112
+ }
113
+ $ groupRestricted = (bool )(string )($ page ['fe_group ' ] ?? '' );
114
+ $ timeRestricted = (int )($ page ['starttime ' ] ?? 0 ) || (int )($ page ['endtime ' ] ?? 0 );
115
+ $ hidden = (int )($ page ['hidden ' ] ?? 0 );
116
+ // Stop as soon as a page in the rootline has extendToSubpages set
117
+ break ;
118
+ }
119
+ }
120
+
121
+ } catch (\Exception ) {
122
+ // if the rootline cannot be resolved (404 because of delete placeholder in workspaces for example)
123
+ // we do not want to fail here but rather continue handling the request to trigger the TSFE 404 handling
124
+ } finally {
125
+ // clear the rootline cache to ensure it's cleanly built with the full context later on.
126
+ $ cacheManager = GeneralUtility::makeInstance (CacheManager::class);
127
+ $ cacheManager ->getCache ('runtime ' )->flushByTag (RootlineUtility::RUNTIME_CACHE_TAG );
128
+ $ cacheManager ->getCache ('rootline ' )->flush ();
129
+ }
130
+ return $ groupRestricted || $ timeRestricted || $ hidden ;
131
+ }
132
+
90
133
/**
91
134
* Checks if the page is hidden in the active workspace + language setup.
92
135
*/
0 commit comments