Total Complexity | 43 |
Total Lines | 310 |
Duplicated Lines | 2.58 % |
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 RequestHandler 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 RequestHandler, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class RequestHandler implements RequestHandlerInterface |
||
40 | { |
||
41 | /** |
||
42 | * Instance of the current TYPO3 bootstrap |
||
43 | * @var Bootstrap |
||
44 | */ |
||
45 | protected $bootstrap; |
||
46 | |||
47 | /** |
||
48 | * Instance of the timetracker |
||
49 | * @var TimeTracker |
||
50 | */ |
||
51 | protected $timeTracker; |
||
52 | |||
53 | /** |
||
54 | * Instance of the TSFE object |
||
55 | * @var TypoScriptFrontendController |
||
56 | */ |
||
57 | protected $controller; |
||
58 | |||
59 | /** |
||
60 | * The request handed over |
||
61 | * @var \Psr\Http\Message\ServerRequestInterface |
||
62 | */ |
||
63 | protected $request; |
||
64 | |||
65 | /** |
||
66 | * Constructor handing over the bootstrap and the original request |
||
67 | * |
||
68 | * @param Bootstrap $bootstrap |
||
69 | */ |
||
70 | public function __construct(Bootstrap $bootstrap) |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Handles a frontend request |
||
77 | * |
||
78 | * @param \Psr\Http\Message\ServerRequestInterface $request |
||
79 | * @return \Psr\Http\Message\ResponseInterface|null |
||
80 | */ |
||
81 | public function handleRequest(\Psr\Http\Message\ServerRequestInterface $request) |
||
82 | { |
||
83 | $response = null; |
||
84 | $this->request = $request; |
||
85 | $this->initializeTimeTracker(); |
||
86 | |||
87 | // Hook to preprocess the current request: |
||
88 | foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'] ?? [] as $hookFunction) { |
||
89 | $hookParameters = []; |
||
90 | GeneralUtility::callUserFunction($hookFunction, $hookParameters, $hookParameters); |
||
91 | } |
||
92 | |||
93 | $this->initializeController(); |
||
94 | |||
95 | if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_force'] |
||
96 | && !GeneralUtility::cmpIP( |
||
97 | GeneralUtility::getIndpEnv('REMOTE_ADDR'), |
||
98 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] |
||
99 | ) |
||
100 | ) { |
||
101 | $this->controller->pageUnavailableAndExit('This page is temporarily unavailable.'); |
||
102 | } |
||
103 | |||
104 | $this->controller->connectToDB(); |
||
105 | |||
106 | // Output compression |
||
107 | // Remove any output produced until now |
||
108 | $this->bootstrap->endOutputBufferingAndCleanPreviousOutput(); |
||
109 | $this->initializeOutputCompression(); |
||
110 | |||
111 | // Initializing the Frontend User |
||
112 | $this->timeTracker->push('Front End user initialized', ''); |
||
113 | $this->controller->initFEuser(); |
||
114 | $this->timeTracker->pull(); |
||
115 | |||
116 | // Initializing a possible logged-in Backend User |
||
117 | /** @var $GLOBALS['BE_USER'] \TYPO3\CMS\Backend\FrontendBackendUserAuthentication */ |
||
118 | $GLOBALS['BE_USER'] = $this->controller->initializeBackendUser(); |
||
119 | |||
120 | // Process the ID, type and other parameters. |
||
121 | // After this point we have an array, $page in TSFE, which is the page-record |
||
122 | // of the current page, $id. |
||
123 | $this->timeTracker->push('Process ID', ''); |
||
124 | // Initialize admin panel since simulation settings are required here: |
||
125 | if ($this->controller->isBackendUserLoggedIn()) { |
||
126 | $GLOBALS['BE_USER']->initializeAdminPanel(); |
||
127 | $this->bootstrap |
||
128 | ->initializeBackendRouter() |
||
129 | ->loadExtTables(); |
||
130 | } |
||
131 | $this->controller->checkAlternativeIdMethods(); |
||
132 | $this->controller->clear_preview(); |
||
133 | $this->controller->determineId(); |
||
134 | |||
135 | // Now, if there is a backend user logged in and he has NO access to this page, |
||
136 | // then re-evaluate the id shown! _GP('ADMCMD_noBeUser') is placed here because |
||
137 | // \TYPO3\CMS\Version\Hook\PreviewHook might need to know if a backend user is logged in. |
||
138 | if ( |
||
139 | $this->controller->isBackendUserLoggedIn() |
||
140 | && (!$GLOBALS['BE_USER']->extPageReadAccess($this->controller->page) || GeneralUtility::_GP('ADMCMD_noBeUser')) |
||
|
|||
141 | ) { |
||
142 | // Remove user |
||
143 | unset($GLOBALS['BE_USER']); |
||
144 | $this->controller->beUserLogin = false; |
||
145 | // Re-evaluate the page-id. |
||
146 | $this->controller->checkAlternativeIdMethods(); |
||
147 | $this->controller->clear_preview(); |
||
148 | $this->controller->determineId(); |
||
149 | } |
||
150 | |||
151 | $this->controller->makeCacheHash(); |
||
152 | $this->timeTracker->pull(); |
||
153 | |||
154 | // Admin Panel & Frontend editing |
||
155 | if ($this->controller->isBackendUserLoggedIn()) { |
||
156 | $GLOBALS['BE_USER']->initializeFrontendEdit(); |
||
157 | if ($GLOBALS['BE_USER']->adminPanel instanceof AdminPanelView) { |
||
158 | $this->bootstrap->initializeLanguageObject(); |
||
159 | } |
||
160 | if ($GLOBALS['BE_USER']->frontendEdit instanceof FrontendEditingController) { |
||
161 | $GLOBALS['BE_USER']->frontendEdit->initConfigOptions(); |
||
162 | } |
||
163 | } |
||
164 | |||
165 | // Starts the template |
||
166 | $this->timeTracker->push('Start Template', ''); |
||
167 | $this->controller->initTemplate(); |
||
168 | $this->timeTracker->pull(); |
||
169 | // Get from cache |
||
170 | $this->timeTracker->push('Get Page from cache', ''); |
||
171 | $this->controller->getFromCache(); |
||
172 | $this->timeTracker->pull(); |
||
173 | // Get config if not already gotten |
||
174 | // After this, we should have a valid config-array ready |
||
175 | $this->controller->getConfigArray(); |
||
176 | // Setting language and locale |
||
177 | $this->timeTracker->push('Setting language and locale', ''); |
||
178 | $this->controller->settingLanguage(); |
||
179 | $this->controller->settingLocale(); |
||
180 | $this->timeTracker->pull(); |
||
181 | |||
182 | // Convert POST data to utf-8 for internal processing if metaCharset is different |
||
183 | $this->controller->convPOSTCharset(); |
||
184 | |||
185 | $this->controller->initializeRedirectUrlHandlers(); |
||
186 | |||
187 | $this->controller->handleDataSubmission(); |
||
188 | |||
189 | // Check for shortcut page and redirect |
||
190 | $this->controller->checkPageForShortcutRedirect(); |
||
191 | $this->controller->checkPageForMountpointRedirect(); |
||
192 | |||
193 | // Generate page |
||
194 | $this->controller->setUrlIdToken(); |
||
195 | $this->timeTracker->push('Page generation', ''); |
||
196 | if ($this->controller->isGeneratePage()) { |
||
197 | $this->controller->generatePage_preProcessing(); |
||
198 | $this->controller->preparePageContentGeneration(); |
||
199 | // Content generation |
||
200 | if (!$this->controller->isINTincScript()) { |
||
201 | PageGenerator::renderContent(); |
||
202 | $this->controller->setAbsRefPrefix(); |
||
203 | } |
||
204 | $this->controller->generatePage_postProcessing(); |
||
205 | } elseif ($this->controller->isINTincScript()) { |
||
206 | $this->controller->preparePageContentGeneration(); |
||
207 | } |
||
208 | $this->controller->releaseLocks(); |
||
209 | $this->timeTracker->pull(); |
||
210 | |||
211 | // Render non-cached parts |
||
212 | if ($this->controller->isINTincScript()) { |
||
213 | $this->timeTracker->push('Non-cached objects', ''); |
||
214 | $this->controller->INTincScript(); |
||
215 | $this->timeTracker->pull(); |
||
216 | } |
||
217 | |||
218 | // Output content |
||
219 | $sendTSFEContent = false; |
||
220 | if ($this->controller->isOutputting()) { |
||
221 | $this->timeTracker->push('Print Content', ''); |
||
222 | $this->controller->processOutput(); |
||
223 | $sendTSFEContent = true; |
||
224 | $this->timeTracker->pull(); |
||
225 | } |
||
226 | // Store session data for fe_users |
||
227 | $this->controller->storeSessionData(); |
||
228 | |||
229 | // Create a Response object when sending content |
||
230 | if ($sendTSFEContent) { |
||
231 | $response = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\Response::class); |
||
232 | } |
||
233 | |||
234 | // Statistics |
||
235 | $GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(true); |
||
236 | if ($sendTSFEContent) { |
||
237 | View Code Duplication | if (isset($this->controller->config['config']['debug'])) { |
|
238 | $includeParseTime = (bool)$this->controller->config['config']['debug']; |
||
239 | } else { |
||
240 | $includeParseTime = !empty($GLOBALS['TYPO3_CONF_VARS']['FE']['debug']); |
||
241 | } |
||
242 | if ($includeParseTime) { |
||
243 | $response = $response->withHeader('X-TYPO3-Parsetime', $this->timeTracker->getParseTime() . 'ms'); |
||
244 | } |
||
245 | } |
||
246 | $this->controller->redirectToExternalUrl(); |
||
247 | // Preview info |
||
248 | $this->controller->previewInfo(); |
||
249 | // Hook for end-of-frontend |
||
250 | $this->controller->hook_eofe(); |
||
251 | // Finish timetracking |
||
252 | $this->timeTracker->pull(); |
||
253 | |||
254 | // Admin panel |
||
255 | if ($this->controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) { |
||
256 | if ($GLOBALS['BE_USER']->isAdminPanelVisible()) { |
||
257 | $this->controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $this->controller->content); |
||
258 | } |
||
259 | } |
||
260 | |||
261 | if ($sendTSFEContent) { |
||
262 | // Send content-length header. |
||
263 | // Notice that all HTML content outside the length of the content-length header will be cut off! |
||
264 | // Therefore content of unknown length from included PHP-scripts and if admin users are logged |
||
265 | // in (admin panel might show...) or if debug mode is turned on, we disable it! |
||
266 | if ( |
||
267 | (!isset($this->controller->config['config']['enableContentLengthHeader']) || $this->controller->config['config']['enableContentLengthHeader']) |
||
268 | && !$this->controller->beUserLogin && !$GLOBALS['TYPO3_CONF_VARS']['FE']['debug'] |
||
269 | && !$this->controller->config['config']['debug'] && !$this->controller->doWorkspacePreview() |
||
270 | ) { |
||
271 | header('Content-Length: ' . strlen($this->controller->content)); |
||
272 | } |
||
273 | $response->getBody()->write($this->controller->content); |
||
274 | } |
||
275 | GeneralUtility::makeInstance(LogManager::class) |
||
276 | ->getLogger(get_class())->debug('END of FRONTEND session', ['_FLUSH' => true]); |
||
277 | return $response; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * This request handler can handle any frontend request. |
||
282 | * |
||
283 | * @param \Psr\Http\Message\ServerRequestInterface $request |
||
284 | * @return bool If the request is not an eID request, TRUE otherwise FALSE |
||
285 | */ |
||
286 | public function canHandleRequest(\Psr\Http\Message\ServerRequestInterface $request) |
||
287 | { |
||
288 | return $request->getQueryParams()['eID'] || $request->getParsedBody()['eID'] ? false : true; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Returns the priority - how eager the handler is to actually handle the |
||
293 | * request. |
||
294 | * |
||
295 | * @return int The priority of the request handler. |
||
296 | */ |
||
297 | public function getPriority() |
||
298 | { |
||
299 | return 50; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Initializes output compression when enabled, could be split up and put into Bootstrap |
||
304 | * at a later point |
||
305 | */ |
||
306 | protected function initializeOutputCompression() |
||
313 | } |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Timetracking started depending if a Backend User is logged in |
||
318 | */ |
||
319 | protected function initializeTimeTracker() |
||
320 | { |
||
321 | $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName']) ?: 'be_typo_user'; |
||
322 | |||
323 | /** @var TimeTracker timeTracker */ |
||
324 | $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class, ($this->request->getCookieParams()[$configuredCookieName] ? true : false)); |
||
325 | $this->timeTracker->start(); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Creates an instance of TSFE and sets it as a global variable |
||
330 | */ |
||
331 | protected function initializeController() |
||
349 | } |
||
350 | } |
||
351 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: