‪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;
30 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
32 
42 {
46  protected ?ContentObjectRenderer ‪$cObj = null;
47 
48  protected ContainerInterface ‪$container;
54 
55  public function ‪__construct(
56  ContainerInterface ‪$container,
62  ) {
63  $this->container = ‪$container;
64  $this->configurationManager = ‪$configurationManager;
65  $this->persistenceManager = ‪$persistenceManager;
66  $this->cacheService = ‪$cacheService;
67  $this->dispatcher = ‪$dispatcher;
68  $this->extbaseRequestBuilder = ‪$extbaseRequestBuilder;
69  }
70 
74  public function ‪setContentObjectRenderer(ContentObjectRenderer ‪$cObj)
75  {
76  $this->cObj = ‪$cObj;
77  }
78 
89  public function ‪initialize(array $configuration): void
90  {
91  if (!‪Environment::isCli()) {
92  if (!isset($configuration['extensionName']) || $configuration['extensionName'] === '') {
93  throw new \RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
94  }
95  if (!isset($configuration['pluginName']) || $configuration['pluginName'] === '') {
96  throw new \RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
97  }
98  }
99  $this->‪initializeConfiguration($configuration);
100  }
101 
108  public function ‪initializeConfiguration(array $configuration): void
109  {
110  $this->cObj ??= $this->container->get(ContentObjectRenderer::class);
111  $this->configurationManager->setContentObject($this->cObj);
112  $this->configurationManager->setConfiguration($configuration);
113  // todo: Shouldn't the configuration manager object – which is a singleton – be stateless?
114  // todo: At this point we give the configuration manager a state, while we could directly pass the
115  // todo: configuration (i.e. controllerName, actionName and such), directly to the request
116  // todo: handler, which then creates stateful request objects.
117  // todo: Once this has changed, \TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder::loadDefaultValues does not need
118  // todo: to fetch this configuration from the configuration manager.
119  }
120 
134  public function ‪run(string $content, array $configuration, ServerRequestInterface $request): string
135  {
136  $this->‪initialize($configuration);
137  return $this->‪handleFrontendRequest($request);
138  }
139 
145  public function ‪handleFrontendRequest(ServerRequestInterface $request): string
146  {
147  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
148  if (!$this->‪isExtbaseRequestCacheable($extbaseRequest)) {
149  if ($this->cObj->getUserObjectType() === ContentObjectRenderer::OBJECTTYPE_USER) {
150  // ContentObjectRenderer::convertToUserIntObject() will recreate the object,
151  // so we have to stop the request here before the action is actually called
152  $this->cObj->convertToUserIntObject();
153  return '';
154  }
155  }
156 
157  // Dispatch the extbase request
158  $response = $this->dispatcher->dispatch($extbaseRequest);
159  if ($response->getStatusCode() >= 300) {
160  // Avoid caching the plugin when we issue a redirect or error response
161  // This means that even when an action is configured as cachable
162  // we avoid the plugin to be cached, but keep the page cache untouched
163  if ($this->cObj->getUserObjectType() === ContentObjectRenderer::OBJECTTYPE_USER) {
164  $this->cObj->convertToUserIntObject();
165  }
166  }
167  // Usually coming from an error action, ensure all caches are cleared
168  if ($response->getStatusCode() === 400) {
169  $this->‪clearCacheOnError();
170  }
171 
172  // In case TSFE is available and this is a json response, we have to let TSFE know we have a specific Content-Type
173  if (($typoScriptFrontendController = (‪$GLOBALS['TSFE'] ?? null)) instanceof ‪TypoScriptFrontendController
174  && $response->hasHeader('Content-Type')
175  ) {
176  $typoScriptFrontendController->setContentType($response->getHeaderLine('Content-Type'));
177  // Do not send the header directly (see below)
178  $response = $response->withoutHeader('Content-Type');
179  }
180 
181  if (headers_sent() === false) {
182  foreach ($response->getHeaders() as $name => $values) {
183  foreach ($values as $value) {
184  header(sprintf('%s: %s', $name, $value));
185  }
186  }
187 
188  // Set status code from extbase response
189  // @todo: Remove when ContentObjectRenderer is response aware
190  if ($response->getStatusCode() >= 300) {
191  header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
192  }
193  }
194  $body = $response->getBody();
195  $body->rewind();
196  $content = $body->getContents();
197  $this->‪resetSingletons();
198  $this->cacheService->clearCachesOfRegisteredPageIds();
199  return $content;
200  }
201 
210  public function ‪handleBackendRequest(ServerRequestInterface $request): ResponseInterface
211  {
212  // build the configuration from the module, included in the current request
213  $module = $request->getAttribute('module');
214  $configuration = [
215  'extensionName' => $module?->getExtensionName(),
216  'pluginName' => $module?->getIdentifier(),
217  ];
218 
219  $this->‪initialize($configuration);
220  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
221  $response = $this->dispatcher->dispatch($extbaseRequest);
222  $this->‪resetSingletons();
223  $this->cacheService->clearCachesOfRegisteredPageIds();
224  return $response;
225  }
226 
230  protected function ‪clearCacheOnError(): void
231  {
232  $extbaseSettings = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
233  if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
234  if (isset(‪$GLOBALS['TSFE'])) {
235  $this->cacheService->clearPageCache([‪$GLOBALS['TSFE']->id]);
236  }
237  }
238  }
239 
243  protected function ‪resetSingletons(): void
244  {
245  $this->persistenceManager->persistAll();
246  }
247 
248  protected function ‪isExtbaseRequestCacheable(‪RequestInterface $extbaseRequest): bool
249  {
250  $controllerClassName = $extbaseRequest->‪getControllerObjectName();
251  $actionName = $extbaseRequest->‪getControllerActionName();
252  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
253  $nonCacheableActions = $frameworkConfiguration['controllerConfiguration'][$controllerClassName]['nonCacheableActions'] ?? null;
254  if (!is_array($nonCacheableActions)) {
255  return true;
256  }
257  return !in_array($actionName, $nonCacheableActions, true);
258  }
259 }
‪TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
Definition: PersistenceManagerInterface.php:22
‪TYPO3\CMS\Extbase\Core\Bootstrap\resetSingletons
‪resetSingletons()
Definition: Bootstrap.php:243
‪TYPO3\CMS\Extbase\Mvc\Dispatcher
Definition: Dispatcher.php:36
‪TYPO3\CMS\Extbase\Core\Bootstrap\$persistenceManager
‪PersistenceManagerInterface $persistenceManager
Definition: Bootstrap.php:50
‪TYPO3\CMS\Extbase\Core\Bootstrap\$dispatcher
‪Dispatcher $dispatcher
Definition: Bootstrap.php:52
‪TYPO3\CMS\Extbase\Mvc\RequestInterface\getControllerObjectName
‪getControllerObjectName()
‪TYPO3\CMS\Extbase\Core\Bootstrap\run
‪string run(string $content, array $configuration, ServerRequestInterface $request)
Definition: Bootstrap.php:134
‪TYPO3\CMS\Extbase\Core\Bootstrap\setContentObjectRenderer
‪setContentObjectRenderer(ContentObjectRenderer $cObj)
Definition: Bootstrap.php:74
‪TYPO3\CMS\Extbase\Core\Bootstrap\initializeConfiguration
‪initializeConfiguration(array $configuration)
Definition: Bootstrap.php:108
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleFrontendRequest
‪handleFrontendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:145
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cObj
‪ContentObjectRenderer $cObj
Definition: Bootstrap.php:46
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleBackendRequest
‪handleBackendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:210
‪TYPO3\CMS\Extbase\Core\Bootstrap\$extbaseRequestBuilder
‪RequestBuilder $extbaseRequestBuilder
Definition: Bootstrap.php:53
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_FRAMEWORK
‪const CONFIGURATION_TYPE_FRAMEWORK
Definition: ConfigurationManagerInterface.php:29
‪TYPO3\CMS\Extbase\Core\Bootstrap\initialize
‪initialize(array $configuration)
Definition: Bootstrap.php:89
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cacheService
‪CacheService $cacheService
Definition: Bootstrap.php:51
‪TYPO3\CMS\Extbase\Core\Bootstrap\$configurationManager
‪ConfigurationManagerInterface $configurationManager
Definition: Bootstrap.php:49
‪TYPO3\CMS\Core\Core\Environment\isCli
‪static isCli()
Definition: Environment.php:145
‪TYPO3\CMS\Extbase\Core\Bootstrap\clearCacheOnError
‪clearCacheOnError()
Definition: Bootstrap.php:230
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:105
‪$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\Extbase\Core\Bootstrap\$container
‪ContainerInterface $container
Definition: Bootstrap.php:48
‪TYPO3\CMS\Extbase\Core
Definition: Bootstrap.php:18
‪TYPO3\CMS\Extbase\Mvc\RequestInterface\getControllerActionName
‪getControllerActionName()
‪TYPO3\CMS\Extbase\Core\Bootstrap\__construct
‪__construct(ContainerInterface $container, ConfigurationManagerInterface $configurationManager, PersistenceManagerInterface $persistenceManager, CacheService $cacheService, Dispatcher $dispatcher, RequestBuilder $extbaseRequestBuilder)
Definition: Bootstrap.php:55
‪TYPO3\CMS\Extbase\Core\Bootstrap\isExtbaseRequestCacheable
‪isExtbaseRequestCacheable(RequestInterface $extbaseRequest)
Definition: Bootstrap.php:248
‪TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder
Definition: RequestBuilder.php:40