051301db28c11061efd25c647fba02c1107ed419
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Dispatcher.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Creates a request an dispatches it to the controller which was specified
27 * by TS Setup, Flexform and returns the content to the v4 framework.
28 *
29 * @package Extbase
30 * @subpackage extbase
31 * @version $ID:$
32 */
33 class Tx_Extbase_Dispatcher {
34
35 /**
36 * @var Tx_Extbase_Reflection_Service
37 */
38 protected $reflectionService;
39
40 /**
41 * @var Tx_Extbase_Persistence_Manager
42 */
43 private static $persistenceManager;
44
45 /**
46 * Creates a request an dispatches it to a controller.
47 *
48 * @param string $content The content
49 * @param array|NULL $configuration The TS configuration array
50 * @return string $content The processed content
51 */
52 public function dispatch($content, $configuration) {
53 if (!is_array($configuration)) {
54 t3lib_div::sysLog('Extbase was not able to dispatch the request. No configuration.', 'extbase', t3lib_div::SYSLOG_SEVERITY_ERROR);
55 return $content;
56 }
57
58 $requestBuilder = t3lib_div::makeInstance('Tx_Extbase_MVC_Web_RequestBuilder');
59 $request = $requestBuilder->initialize($configuration);
60 $request = $requestBuilder->build();
61 $response = t3lib_div::makeInstance('Tx_Extbase_MVC_Web_Response');
62
63 $persistenceManager = self::getPersistenceManager($configuration, $this->extractStoragePageId());
64
65 $dispatchLoopCount = 0;
66 while (!$request->isDispatched()) {
67 if ($dispatchLoopCount++ > 99) throw new Tx_Extbase_MVC_Exception_InfiniteLoop('Could not ultimately dispatch the request after ' . $dispatchLoopCount . ' iterations.', 1217839467);
68 $controller = $this->getPreparedController($request);
69 try {
70 $controller->processRequest($request, $response);
71 } catch (Tx_Extbase_Exception_StopAction $ignoredException) {
72 } catch (Tx_Extbase_Exception_InvalidArgumentValue $exception) {
73 return '';
74 }
75 }
76
77 $persistenceManager->persistAll();
78 $this->reflectionService->shutdown();
79 if (count($response->getAdditionalHeaderData()) > 0) {
80 $GLOBALS['TSFE']->additionalHeaderData[$request->getControllerExtensionName()] = implode("\n", $response->getAdditionalHeaderData());
81 }
82 $response->sendHeaders();
83 return $response->getContent();
84 }
85
86 /**
87 * Extracts the storage PID from $this->cObj->data['pages']. ONLY ALLOWS ONE STORAGE PID!
88 * If this one is empty, tries to use $this->cObj->parentRecord->data['storage_pid']. If both are empty, uses current page.
89 *
90 * @return integer
91 * @throws InvalidArgumentException if more than one storage page ID is given
92 */
93 protected function extractStoragePageId() {
94 if (is_string($this->cObj->data['pages'])) {
95 if (count(explode(',', $this->cObj->data['pages'])) > 1) {
96 throw new InvalidArgumentException('More than one storage page ID given. This is currently not supported.', 1247597243);
97 }
98 return (int)$this->cObj->data['pages'];
99 }
100
101 if ($this->cObj->parentRecord->data['storage_pid'] > 0) {
102 return (int)$this->cObj->parentRecord->data['storage_pid'];
103 }
104 return $GLOBALS['TSFE']->id;
105 }
106
107 /**
108 * Builds and returns a controller
109 *
110 * @param Tx_Extbase_MVC_Web_Request $request
111 * @return Tx_Extbase_MVC_Controller_ControllerInterface The prepared controller
112 */
113 protected function getPreparedController(Tx_Extbase_MVC_Web_Request $request) {
114 $controllerObjectName = $request->getControllerObjectName();
115 $controller = t3lib_div::makeInstance($controllerObjectName);
116 if (!$controller instanceof Tx_Extbase_MVC_Controller_ControllerInterface) {
117 throw new Tx_Extbase_Exception_InvalidController('Invalid controller "' . $request->getControllerObjectName() . '". The controller must implement the Tx_Extbase_MVC_Controller_ControllerInterface.', 1202921619);
118 }
119 $propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
120 $controller->injectPropertyMapper($propertyMapper);
121 $controller->injectSettings($this->getSettings($request));
122 $cacheManager = t3lib_div::makeInstance('t3lib_cache_Manager');
123 $this->reflectionService = t3lib_div::makeInstance('Tx_Extbase_Reflection_Service');
124 try {
125 $this->reflectionService->setCache($cacheManager->getCache('Tx_Extbase_Reflection'));
126 } catch (t3lib_cache_exception_NoSuchCache $exception) {
127 $cacheFactory = t3lib_div::makeInstance('t3lib_cache_Factory');
128 $cacheFactory->create(
129 'Tx_Extbase_Reflection',
130 't3lib_cache_frontend_VariableFrontend',
131 $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['Tx_Extbase_Reflection']['backend'],
132 $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['Tx_Extbase_Reflection']['options']
133 );
134 $this->reflectionService->setCache($cacheManager->getCache('Tx_Extbase_Reflection'));
135 }
136 if (!$this->reflectionService->isInitialized()) {
137 $this->reflectionService->initialize();
138 }
139 $validatorResolver = t3lib_div::makeInstance('Tx_Extbase_Validation_ValidatorResolver');
140 $validatorResolver->injectObjectManager(t3lib_div::makeInstance('Tx_Extbase_Object_Manager'));
141 $validatorResolver->injectReflectionService($this->reflectionService);
142 $controller->injectValidatorResolver($validatorResolver);
143 $controller->injectReflectionService($this->reflectionService);
144 return $controller;
145 }
146
147 /**
148 * Builds the settings by overlaying TS Setup with FlexForm values of the extension
149 * and returns them as a plain array (with no trailing dots).
150 *
151 * @param Tx_Extbase_MVC_Web_Request $request
152 * @return array The settings array
153 */
154 protected function getSettings(Tx_Extbase_MVC_Web_Request $request) {
155 $extensionName = $request->getControllerExtensionName();
156 $configurationSources = array();
157 $configurationSources[] = t3lib_div::makeInstance('Tx_Extbase_Configuration_Source_TypoScriptSource');
158 if (!empty($this->cObj->data['pi_flexform'])) {
159 $configurationSource = t3lib_div::makeInstance('Tx_Extbase_Configuration_Source_FlexFormSource');
160 $configurationSource->setFlexFormContent($this->cObj->data['pi_flexform']);
161 $configurationSources[] = $configurationSource;
162 }
163 $configurationManager = t3lib_div::makeInstance('Tx_Extbase_Configuration_Manager', $configurationSources);
164 return $configurationManager->getSettings($extensionName);
165 }
166
167 /**
168 * This function prepares and returns the Persistance Manager
169 *
170 * @param array $configuration The given configuration
171 * @param integer $storagePageId Storage page ID to to read and write records.
172 * @return Tx_Extbase_Persistence_Manager A (singleton) instance of the Persistence Manager
173 */
174 public static function getPersistenceManager(array $configuration = array(), $storagePageId = 0) {
175 if (self::$persistenceManager === NULL) {
176 $queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'); // singleton
177 $queryFactory->setStoragePageId($storagePageId);
178
179 $persistenceSession = t3lib_div::makeInstance('Tx_Extbase_Persistence_Session'); // singleton
180 $storageBackend = t3lib_div::makeInstance('Tx_Extbase_Persistence_Storage_Typo3DbBackend', $GLOBALS['TYPO3_DB']); // singleton
181 if (is_array($configuration) && isset($configuration['enableAutomaticCacheClearing']) && $configuration['enableAutomaticCacheClearing'] === '1') {
182 $storageBackend->setAutomaticCacheClearing(TRUE);
183 } else {
184 $storageBackend->setAutomaticCacheClearing(FALSE);
185 }
186 $dataMapper = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMapper'); // singleton
187
188 $persistenceBackend = t3lib_div::makeInstance('Tx_Extbase_Persistence_Backend', $persistenceSession, $storageBackend, $storagePageId); // singleton
189 $persistenceBackend->injectDataMapper($dataMapper);
190 $persistenceBackend->injectIdentityMap(t3lib_div::makeInstance('Tx_Extbase_Persistence_IdentityMap'));
191 $persistenceBackend->injectQOMFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_QOM_QueryObjectModelFactory', $storageBackend, $dataMapper));
192 $persistenceBackend->injectValueFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_ValueFactory'));
193
194 $persistenceManager = t3lib_div::makeInstance('Tx_Extbase_Persistence_Manager'); // singleton
195 $persistenceManager->injectBackend($persistenceBackend);
196 $persistenceManager->injectSession($persistenceSession);
197
198 self::$persistenceManager = $persistenceManager;
199 }
200
201 return self::$persistenceManager;
202 }
203
204 /**
205 * Loads php files containing classes or interfaces found in the classes directory of
206 * an extension.
207 *
208 * @param string $className: Name of the class/interface to load
209 * @uses t3lib_extMgm::extPath()
210 * @return void
211 */
212 public static function autoloadClass($className) {
213 $classNameParts = explode('_', $className);
214 $extensionKey = t3lib_div::camelCaseToLowerCaseUnderscored($classNameParts[1]);
215 if (t3lib_extMgm::isLoaded($extensionKey)) {
216 if ($classNameParts[0] === 'ux') {
217 array_shift($classNameParts);
218 }
219 $className = implode('_', $classNameParts);
220 if (count($classNameParts) > 2 && $classNameParts[0] === 'Tx') {
221 $classFilePathAndName = t3lib_extMgm::extPath(t3lib_div::camelCaseToLowerCaseUnderscored($classNameParts[1])) . 'Classes/';
222 $classFilePathAndName .= implode(array_slice($classNameParts, 2, -1), '/') . '/';
223 $classFilePathAndName .= array_pop($classNameParts) . '.php';
224 }
225 if (isset($classFilePathAndName) && file_exists($classFilePathAndName)) {
226 require_once($classFilePathAndName);
227 }
228 }
229 }
230
231 }
232 ?>