‪TYPO3CMS  ‪main
Bootstrap.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Container\ContainerInterface;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
32 
42 {
44 
45  public function ‪__construct(
46  protected readonly ContainerInterface $container,
47  protected readonly ‪ConfigurationManagerInterface $configurationManager,
48  protected readonly ‪PersistenceManagerInterface $persistenceManager,
49  protected readonly ‪CacheService $cacheService,
50  protected readonly ‪Dispatcher $dispatcher,
51  protected readonly ‪RequestBuilder $extbaseRequestBuilder
52  ) {}
53 
59  {
60  $this->cObj = ‪$cObj;
61  }
62 
73  public function ‪initialize(array $configuration, ServerRequestInterface $request): ServerRequestInterface
74  {
75  if (!‪Environment::isCli()) {
76  if (!isset($configuration['extensionName']) || $configuration['extensionName'] === '') {
77  throw new \RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
78  }
79  if (!isset($configuration['pluginName']) || $configuration['pluginName'] === '') {
80  throw new \RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
81  }
82  }
83  return $this->‪initializeConfiguration($configuration, $request);
84  }
85 
92  public function ‪initializeConfiguration(array $configuration, ServerRequestInterface $request): ServerRequestInterface
93  {
94  if ($this->cObj === null) {
95  // @todo: While the frontend sets the current cObj, a backend extbase request does not.
96  // It is currently not clear if the backend should have a dummy cObj as well.
97  // For now, extbase initializes one.
98  $this->cObj = $this->container->get(ContentObjectRenderer::class);
99  $this->cObj->setRequest($request);
100  }
101  $this->configurationManager->setRequest($request);
102  $this->configurationManager->setConfiguration($configuration);
103  return $request;
104  // todo: Outdated todo, recheck in v13.
105  // Shouldn't the configuration manager object – which is a singleton – be stateless?
106  // At this point we give the configuration manager a state, while we could directly pass the
107  // configuration (i.e. controllerName, actionName and such), directly to the request
108  // handler, which then creates stateful request objects.
109  // Once this has changed, \TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder::loadDefaultValues does not need
110  // to fetch this configuration from the configuration manager.
111  }
112 
126  public function ‪run(string $content, array $configuration, ServerRequestInterface $request): string
127  {
128  $request = $this->‪initialize($configuration, $request);
129  return $this->‪handleFrontendRequest($request);
130  }
131 
137  public function ‪handleFrontendRequest(ServerRequestInterface $request): string
138  {
139  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
140  if (!$this->‪isExtbaseRequestCacheable($extbaseRequest)) {
141  if ($this->cObj->getUserObjectType() === ‪ContentObjectRenderer::OBJECTTYPE_USER) {
142  // ContentObjectRenderer::convertToUserIntObject() will recreate the object,
143  // so we have to stop the request here before the action is actually called
144  $this->cObj->convertToUserIntObject();
145  return '';
146  }
147  }
148 
149  // Dispatch the extbase request
150  $response = $this->dispatcher->dispatch($extbaseRequest);
151  if ($response->getStatusCode() >= 300) {
152  // Avoid caching the plugin when we issue a redirect or error response
153  // This means that even when an action is configured as cachable
154  // we avoid the plugin to be cached, but keep the page cache untouched
155  if ($this->cObj->getUserObjectType() === ‪ContentObjectRenderer::OBJECTTYPE_USER) {
156  $this->cObj->convertToUserIntObject();
157  }
158  }
159  // Usually coming from an error action, ensure all caches are cleared
160  if ($response->getStatusCode() === 400) {
161  $this->‪clearCacheOnError($request);
162  }
163 
164  // If TypoScriptFrontendController has been properly set up and this is a json response,
165  // we let TypoScriptFrontendController know we have a specific Content-Type.
166  $typoScriptFrontendController = $request->getAttribute('frontend.controller');
167  if ($typoScriptFrontendController instanceof ‪TypoScriptFrontendController && $response->hasHeader('Content-Type')) {
168  $typoScriptFrontendController->setContentType($response->getHeaderLine('Content-Type'));
169  // Do not send the header directly (see below)
170  $response = $response->withoutHeader('Content-Type');
171  }
172 
173  if (headers_sent() === false) {
174  foreach ($response->getHeaders() as $name => $values) {
175  foreach ($values as $value) {
176  header(sprintf('%s: %s', $name, $value));
177  }
178  }
179 
180  // Set status code from extbase response
181  // @todo: Remove when ContentObjectRenderer is response aware
182  if ($response->getStatusCode() >= 300) {
183  header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
184  }
185  }
186  $body = $response->getBody();
187  $body->rewind();
188  $content = $body->getContents();
189  $this->‪resetSingletons();
190  $this->cacheService->clearCachesOfRegisteredPageIds();
191  return $content;
192  }
193 
201  public function ‪handleBackendRequest(ServerRequestInterface $request): ResponseInterface
202  {
203  // build the configuration from the module, included in the current request
204  $module = $request->getAttribute('module');
205  $configuration = [
206  'extensionName' => $module?->getExtensionName(),
207  'pluginName' => $module?->getIdentifier(),
208  ];
209 
210  $request = $this->‪initialize($configuration, $request);
211  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
212  $response = $this->dispatcher->dispatch($extbaseRequest);
213  $this->‪resetSingletons();
214  $this->cacheService->clearCachesOfRegisteredPageIds();
215  return $response;
216  }
217 
221  protected function ‪clearCacheOnError(ServerRequestInterface $request): void
222  {
223  $extbaseSettings = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
224  if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
225  $pageId = $request->getAttribute('frontend.page.information')?->getId();
226  if ($pageId !== null) {
227  $this->cacheService->clearPageCache([$pageId]);
228  }
229  }
230  }
231 
235  protected function ‪resetSingletons(): void
236  {
237  $this->persistenceManager->persistAll();
238  }
239 
240  protected function ‪isExtbaseRequestCacheable(‪RequestInterface $extbaseRequest): bool
241  {
242  $controllerClassName = $extbaseRequest->‪getControllerObjectName();
243  $actionName = $extbaseRequest->‪getControllerActionName();
244  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
245  $nonCacheableActions = $frameworkConfiguration['controllerConfiguration'][$controllerClassName]['nonCacheableActions'] ?? null;
246  if (!is_array($nonCacheableActions)) {
247  return true;
248  }
249  return !in_array($actionName, $nonCacheableActions, true);
250  }
251 }
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\OBJECTTYPE_USER
‪const OBJECTTYPE_USER
Definition: ContentObjectRenderer.php:365
‪TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
Definition: PersistenceManagerInterface.php:24
‪TYPO3\CMS\Extbase\Core\Bootstrap\resetSingletons
‪resetSingletons()
Definition: Bootstrap.php:235
‪TYPO3\CMS\Extbase\Mvc\Dispatcher
Definition: Dispatcher.php:36
‪TYPO3\CMS\Extbase\Mvc\RequestInterface\getControllerObjectName
‪getControllerObjectName()
‪TYPO3\CMS\Extbase\Core\Bootstrap\run
‪string run(string $content, array $configuration, ServerRequestInterface $request)
Definition: Bootstrap.php:126
‪TYPO3\CMS\Extbase\Core\Bootstrap\setContentObjectRenderer
‪setContentObjectRenderer(ContentObjectRenderer $cObj)
Definition: Bootstrap.php:58
‪TYPO3\CMS\Extbase\Core\Bootstrap\clearCacheOnError
‪clearCacheOnError(ServerRequestInterface $request)
Definition: Bootstrap.php:221
‪TYPO3\CMS\Extbase\Core\Bootstrap\initializeConfiguration
‪initializeConfiguration(array $configuration, ServerRequestInterface $request)
Definition: Bootstrap.php:92
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleFrontendRequest
‪handleFrontendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:137
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cObj
‪ContentObjectRenderer $cObj
Definition: Bootstrap.php:43
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleBackendRequest
‪handleBackendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:201
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_FRAMEWORK
‪const CONFIGURATION_TYPE_FRAMEWORK
Definition: ConfigurationManagerInterface.php:29
‪TYPO3\CMS\Core\Core\Environment\isCli
‪static isCli()
Definition: Environment.php:145
‪TYPO3\CMS\Extbase\Core\Bootstrap\__construct
‪__construct(protected readonly ContainerInterface $container, protected readonly ConfigurationManagerInterface $configurationManager, protected readonly PersistenceManagerInterface $persistenceManager, protected readonly CacheService $cacheService, protected readonly Dispatcher $dispatcher, protected readonly RequestBuilder $extbaseRequestBuilder)
Definition: Bootstrap.php:45
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:58
‪TYPO3\CMS\Extbase\Core\Bootstrap
Definition: Bootstrap.php:42
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Extbase\Service\CacheService
Definition: CacheService.php:34
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:102
‪TYPO3\CMS\Extbase\Core
Definition: Bootstrap.php:18
‪TYPO3\CMS\Extbase\Mvc\RequestInterface\getControllerActionName
‪getControllerActionName()
‪TYPO3\CMS\Extbase\Core\Bootstrap\isExtbaseRequestCacheable
‪isExtbaseRequestCacheable(RequestInterface $extbaseRequest)
Definition: Bootstrap.php:240
‪TYPO3\CMS\Extbase\Core\Bootstrap\initialize
‪initialize(array $configuration, ServerRequestInterface $request)
Definition: Bootstrap.php:73
‪TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder
Definition: RequestBuilder.php:40