‪TYPO3CMS  11.5
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 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
34 
42 {
46  public static ‪$persistenceClasses = [];
47 
53  protected ?ContentObjectRenderer ‪$cObj = null;
54 
55  protected ContainerInterface ‪$container;
62 
63  public function ‪__construct(
64  ContainerInterface ‪$container,
71  ) {
72  $this->container = ‪$container;
73  $this->configurationManager = ‪$configurationManager;
74  $this->persistenceManager = ‪$persistenceManager;
75  $this->requestHandlerResolver = ‪$requestHandlerResolver;
76  $this->cacheService = ‪$cacheService;
77  $this->dispatcher = ‪$dispatcher;
78  $this->extbaseRequestBuilder = ‪$extbaseRequestBuilder;
79  }
80 
86  public function ‪setContentObjectRenderer(ContentObjectRenderer ‪$cObj)
87  {
88  $this->cObj = ‪$cObj;
89  }
90 
101  public function ‪initialize(array $configuration): void
102  {
103  if (!‪Environment::isCli()) {
104  if (!isset($configuration['extensionName']) || $configuration['extensionName'] === '') {
105  throw new \RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
106  }
107  if (!isset($configuration['pluginName']) || $configuration['pluginName'] === '') {
108  throw new \RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
109  }
110  }
111  $this->‪initializeConfiguration($configuration);
112  }
113 
121  public function ‪initializeConfiguration(array $configuration): void
122  {
123  $this->cObj ??= $this->container->get(ContentObjectRenderer::class);
124  $this->configurationManager->setContentObject($this->cObj);
125  $this->configurationManager->setConfiguration($configuration);
126  // todo: Shouldn't the configuration manager object – which is a singleton – be stateless?
127  // todo: At this point we give the configuration manager a state, while we could directly pass the
128  // todo: configuration (i.e. controllerName, actionName and such), directly to the request
129  // todo: handler, which then creates stateful request objects.
130  // todo: Once this has changed, \TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder::loadDefaultValues does not need
131  // todo: to fetch this configuration from the configuration manager.
132  }
133 
144  public function ‪run(string $content, array $configuration, ?ServerRequestInterface $request = null): string
145  {
146  $request = $request ?? ‪$GLOBALS['TYPO3_REQUEST'];
147  $this->‪initialize($configuration);
148  return $this->‪handleFrontendRequest($request);
149  }
150 
151  protected function ‪handleFrontendRequest(ServerRequestInterface $request): string
152  {
153  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
154  if (!$this->‪isExtbaseRequestCacheable($extbaseRequest)) {
155  if ($this->cObj->getUserObjectType() === ContentObjectRenderer::OBJECTTYPE_USER) {
156  // ContentObjectRenderer::convertToUserIntObject() will recreate the object,
157  // so we have to stop the request here before the action is actually called
158  $this->cObj->convertToUserIntObject();
159  return '';
160  }
161  }
162 
163  // Dispatch the extbase request
164  $requestHandler = $this->requestHandlerResolver->resolveRequestHandler($extbaseRequest);
165  $response = $requestHandler->handleRequest($extbaseRequest);
166  if ($response->getStatusCode() >= 300) {
167  // Avoid caching the plugin when we issue a redirect or error response
168  // This means that even when an action is configured as cachable
169  // we avoid the plugin to be cached, but keep the page cache untouched
170  if ($this->cObj->getUserObjectType() === ContentObjectRenderer::OBJECTTYPE_USER) {
171  $this->cObj->convertToUserIntObject();
172  }
173  }
174  // Usually coming from an error action, ensure all caches are cleared
175  if ($response->getStatusCode() === 400) {
176  $this->‪clearCacheOnError();
177  }
178 
179  // In case TSFE is available and this is a json response, we have to let TSFE know we have a specific Content-Type
180  if (($typoScriptFrontendController = (‪$GLOBALS['TSFE'] ?? null)) instanceof ‪TypoScriptFrontendController
181  && $response->hasHeader('Content-Type')
182  ) {
183  $typoScriptFrontendController->setContentType($response->getHeaderLine('Content-Type'));
184  // Do not send the header directly (see below)
185  $response = $response->withoutHeader('Content-Type');
186  }
187 
188  if (headers_sent() === false) {
189  foreach ($response->getHeaders() as $name => $values) {
190  foreach ($values as $value) {
191  header(sprintf('%s: %s', $name, $value));
192  }
193  }
194 
195  // Set status code from extbase response
196  // @todo: Remove when ContentObjectRenderer is response aware
197  if ($response->getStatusCode() >= 300) {
198  header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
199  }
200  }
201  $body = $response->getBody();
202  $body->rewind();
203  $content = $body->getContents();
204  $this->‪resetSingletons();
205  $this->cacheService->clearCachesOfRegisteredPageIds();
206  return $content;
207  }
208 
218  public function ‪handleBackendRequest(ServerRequestInterface $request): ResponseInterface
219  {
220  // build the configuration from the Server request / route
222  $route = $request->getAttribute('route');
223  $moduleConfiguration = $route->getOption('moduleConfiguration');
224  $configuration = [
225  'extensionName' => $moduleConfiguration['extensionName'],
226  'pluginName' => $route->getOption('moduleName'),
227  ];
228 
229  $this->‪initialize($configuration);
230  $extbaseRequest = $this->extbaseRequestBuilder->build($request);
231  $response = $this->dispatcher->dispatch($extbaseRequest);
232  $this->‪resetSingletons();
233  $this->cacheService->clearCachesOfRegisteredPageIds();
234  return $response;
235  }
236 
240  protected function ‪clearCacheOnError(): void
241  {
242  $extbaseSettings = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
243  if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
244  if (isset(‪$GLOBALS['TSFE'])) {
245  $this->cacheService->clearPageCache([‪$GLOBALS['TSFE']->id]);
246  }
247  }
248  }
249 
253  protected function ‪resetSingletons(): void
254  {
255  $this->persistenceManager->persistAll();
256  }
257 
258  protected function ‪isExtbaseRequestCacheable(‪RequestInterface $extbaseRequest): bool
259  {
260  $controllerClassName = $extbaseRequest->‪getControllerObjectName();
261  $actionName = $extbaseRequest->getControllerActionName();
262  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
263  $nonCacheableActions = $frameworkConfiguration['controllerConfiguration'][$controllerClassName]['nonCacheableActions'] ?? null;
264  if (!is_array($nonCacheableActions)) {
265  return true;
266  }
267  return !in_array($actionName, $nonCacheableActions, true);
268  }
269 }
‪TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
Definition: PersistenceManagerInterface.php:22
‪TYPO3\CMS\Extbase\Core\Bootstrap\resetSingletons
‪resetSingletons()
Definition: Bootstrap.php:252
‪TYPO3\CMS\Extbase\Mvc\Dispatcher
Definition: Dispatcher.php:38
‪TYPO3\CMS\Extbase\Core\Bootstrap\$persistenceManager
‪PersistenceManagerInterface $persistenceManager
Definition: Bootstrap.php:56
‪TYPO3\CMS\Extbase\Core\Bootstrap\$dispatcher
‪Dispatcher $dispatcher
Definition: Bootstrap.php:59
‪TYPO3\CMS\Extbase\Core\Bootstrap\setContentObjectRenderer
‪setContentObjectRenderer(ContentObjectRenderer $cObj)
Definition: Bootstrap.php:85
‪TYPO3\CMS\Extbase\Core\Bootstrap\initializeConfiguration
‪initializeConfiguration(array $configuration)
Definition: Bootstrap.php:120
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleFrontendRequest
‪handleFrontendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:150
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cObj
‪ContentObjectRenderer $cObj
Definition: Bootstrap.php:52
‪TYPO3\CMS\Backend\Routing\Route
Definition: Route.php:24
‪TYPO3\CMS\Extbase\Core\Bootstrap\$extbaseRequestBuilder
‪RequestBuilder $extbaseRequestBuilder
Definition: Bootstrap.php:60
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_FRAMEWORK
‪const CONFIGURATION_TYPE_FRAMEWORK
Definition: ConfigurationManagerInterface.php:29
‪TYPO3\CMS\Extbase\Core\Bootstrap\run
‪string run(string $content, array $configuration, ?ServerRequestInterface $request=null)
Definition: Bootstrap.php:143
‪TYPO3\CMS\Extbase\Core\Bootstrap\initialize
‪initialize(array $configuration)
Definition: Bootstrap.php:100
‪TYPO3\CMS\Extbase\Core\Bootstrap\$cacheService
‪CacheService $cacheService
Definition: Bootstrap.php:58
‪TYPO3\CMS\Extbase\Core\Bootstrap\$configurationManager
‪ConfigurationManagerInterface $configurationManager
Definition: Bootstrap.php:55
‪TYPO3\CMS\Extbase\Mvc\RequestInterface\getControllerObjectName
‪string getControllerObjectName()
‪TYPO3\CMS\Extbase\Core\Bootstrap\clearCacheOnError
‪clearCacheOnError()
Definition: Bootstrap.php:239
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:27
‪TYPO3\CMS\Extbase\Mvc\RequestHandlerResolver
Definition: RequestHandlerResolver.php:27
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:104
‪$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:43
‪TYPO3\CMS\Extbase\Service\CacheService
Definition: CacheService.php:35
‪TYPO3\CMS\Extbase\Core\Bootstrap\$container
‪ContainerInterface $container
Definition: Bootstrap.php:54
‪TYPO3\CMS\Extbase\Core
Definition: Bootstrap.php:18
‪TYPO3\CMS\Extbase\Core\Bootstrap\$requestHandlerResolver
‪RequestHandlerResolver $requestHandlerResolver
Definition: Bootstrap.php:57
‪TYPO3\CMS\Extbase\Core\Bootstrap\$persistenceClasses
‪static array $persistenceClasses
Definition: Bootstrap.php:45
‪TYPO3\CMS\Core\Core\Environment\isCli
‪static bool isCli()
Definition: Environment.php:162
‪TYPO3\CMS\Extbase\Core\Bootstrap\isExtbaseRequestCacheable
‪isExtbaseRequestCacheable(RequestInterface $extbaseRequest)
Definition: Bootstrap.php:257
‪TYPO3\CMS\Extbase\Core\Bootstrap\__construct
‪__construct(ContainerInterface $container, ConfigurationManagerInterface $configurationManager, PersistenceManagerInterface $persistenceManager, RequestHandlerResolver $requestHandlerResolver, CacheService $cacheService, Dispatcher $dispatcher, RequestBuilder $extbaseRequestBuilder)
Definition: Bootstrap.php:62
‪TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder
Definition: RequestBuilder.php:37
‪TYPO3\CMS\Extbase\Core\Bootstrap\handleBackendRequest
‪ResponseInterface handleBackendRequest(ServerRequestInterface $request)
Definition: Bootstrap.php:217