‪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  }
54 
60  {
61  $this->cObj = ‪$cObj;
62  }
63 
74  public function ‪initialize(array $configuration, ServerRequestInterface $request): ServerRequestInterface
75  {
76  if (!‪Environment::isCli()) {
77  if (!isset($configuration['extensionName']) || $configuration['extensionName'] === '') {
78  throw new \RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
79  }
80  if (!isset($configuration['pluginName']) || $configuration['pluginName'] === '') {
81  throw new \RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
82  }
83  }
84  return $this->‪initializeConfiguration($configuration, $request);
85  }
86 
93  public function ‪initializeConfiguration(array $configuration, ServerRequestInterface $request): ServerRequestInterface
94  {
95  if ($this->cObj === null) {
96  // @todo: While the frontend sets the current cObj, a backend extbase request does not.
97  // It is currently not clear if the backend should have a dummy cObj as well.
98  // For now, extbase initializes one.
99  $this->cObj = $this->container->get(ContentObjectRenderer::class);
100  $this->cObj->setRequest($request);
101  }
102  $this->configurationManager->setRequest($request);
103  $this->configurationManager->setConfiguration($configuration);
104  return $request;
105  // todo: Outdated todo, recheck in v13.
106  // Shouldn't the configuration manager object – which is a singleton – be stateless?
107  // At this point we give the configuration manager a state, while we could directly pass the
108  // configuration (i.e. controllerName, actionName and such), directly to the request
109  // handler, which then creates stateful request objects.
110  // Once this has changed, \TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder::loadDefaultValues does not need
111  // to fetch this configuration from the configuration manager.
112  }
113 
127  public function ‪run(string $content, array $configuration, ServerRequestInterface $request): string
128  {
129  $request = $this->‪initialize($configuration, $request);
130  return $this->‪handleFrontendRequest($request);
131  }
132 
138  public function ‪handleFrontendRequest(ServerRequestInterface $request): string
139  {
140  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
141  if (!$this->‪isExtbaseRequestCacheable($extbaseRequest)) {
142  if ($this->cObj->getUserObjectType() === ‪ContentObjectRenderer::OBJECTTYPE_USER) {
143  // ContentObjectRenderer::convertToUserIntObject() will recreate the object,
144  // so we have to stop the request here before the action is actually called
145  $this->cObj->convertToUserIntObject();
146  return '';
147  }
148  }
149 
150  // Dispatch the extbase request
151  $response = $this->dispatcher->dispatch($extbaseRequest);
152  if ($response->getStatusCode() >= 300) {
153  // Avoid caching the plugin when we issue a redirect or error response
154  // This means that even when an action is configured as cachable
155  // we avoid the plugin to be cached, but keep the page cache untouched
156  if ($this->cObj->getUserObjectType() === ‪ContentObjectRenderer::OBJECTTYPE_USER) {
157  $this->cObj->convertToUserIntObject();
158  }
159  }
160  // Usually coming from an error action, ensure all caches are cleared
161  if ($response->getStatusCode() === 400) {
162  $this->‪clearCacheOnError();
163  }
164 
165  // In case TSFE is available and this is a json response, we have to let TSFE know we have a specific Content-Type
166  if (($typoScriptFrontendController = (‪$GLOBALS['TSFE'] ?? null)) instanceof ‪TypoScriptFrontendController
167  && $response->hasHeader('Content-Type')
168  ) {
169  $typoScriptFrontendController->setContentType($response->getHeaderLine('Content-Type'));
170  // Do not send the header directly (see below)
171  $response = $response->withoutHeader('Content-Type');
172  }
173 
174  if (headers_sent() === false) {
175  foreach ($response->getHeaders() as $name => $values) {
176  foreach ($values as $value) {
177  header(sprintf('%s: %s', $name, $value));
178  }
179  }
180 
181  // Set status code from extbase response
182  // @todo: Remove when ContentObjectRenderer is response aware
183  if ($response->getStatusCode() >= 300) {
184  header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
185  }
186  }
187  $body = $response->getBody();
188  $body->rewind();
189  $content = $body->getContents();
190  $this->‪resetSingletons();
191  $this->cacheService->clearCachesOfRegisteredPageIds();
192  return $content;
193  }
194 
202  public function ‪handleBackendRequest(ServerRequestInterface $request): ResponseInterface
203  {
204  // build the configuration from the module, included in the current request
205  $module = $request->getAttribute('module');
206  $configuration = [
207  'extensionName' => $module?->getExtensionName(),
208  'pluginName' => $module?->getIdentifier(),
209  ];
210 
211  $request = $this->‪initialize($configuration, $request);
212  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
213  $response = $this->dispatcher->dispatch($extbaseRequest);
214  $this->‪resetSingletons();
215  $this->cacheService->clearCachesOfRegisteredPageIds();
216  return $response;
217  }
218 
222  protected function ‪clearCacheOnError(): void
223  {
224  $extbaseSettings = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
225  if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
226  if (isset(‪$GLOBALS['TSFE'])) {
227  $this->cacheService->clearPageCache([‪$GLOBALS['TSFE']->id]);
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:371
‪TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
Definition: PersistenceManagerInterface.php:22
‪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:127
‪TYPO3\CMS\Extbase\Core\Bootstrap\setContentObjectRenderer
‪setContentObjectRenderer(ContentObjectRenderer $cObj)
Definition: Bootstrap.php:59
‪TYPO3\CMS\Extbase\Core\Bootstrap\initializeConfiguration
‪initializeConfiguration(array $configuration, ServerRequestInterface $request)
Definition: Bootstrap.php:93
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleFrontendRequest
‪handleFrontendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:138
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cObj
‪ContentObjectRenderer $cObj
Definition: Bootstrap.php:43
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleBackendRequest
‪handleBackendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:202
‪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\Core\Bootstrap\clearCacheOnError
‪clearCacheOnError()
Definition: Bootstrap.php:222
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:102
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪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:35
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:90
‪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:74
‪TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder
Definition: RequestBuilder.php:40