[+BUGFIX] Extbase (Persistence): Extbase still used PHPs current() on some QueryResul...
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / Extension.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 * Utilities to manage plugins and modules of an extension. Also useful to auto-generate the autoloader registry
27 * file ext_autoload.php.
28 *
29 * @package Extbase
30 * @subpackage Utility
31 * @version $ID:$
32 */
33 class Tx_Extbase_Utility_Extension {
34
35 /**
36 * Add auto-generated TypoScript to configure the Extbase Dispatcher.
37 *
38 * When adding a frontend plugin you will have to add both an entry to the TCA definition
39 * of tt_content table AND to the TypoScript template which must initiate the rendering.
40 * Since the static template with uid 43 is the "content.default" and practically always
41 * used for rendering the content elements it's very useful to have this function automatically
42 * adding the necessary TypoScript for calling the appropriate controller and action of your plugin.
43 * It will also work for the extension "css_styled_content"
44 * FOR USE IN ext_localconf.php FILES
45 * Usage: 2
46 *
47 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
48 * @param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
49 * @param string $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
50 * @param string $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
51 * @param string $defaultControllerAction is an optional array controller name (as array key) and action name (as array value) that should be called as default
52 * @return void
53 */
54 static public function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = array()) {
55 if (empty($pluginName)) {
56 throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
57 }
58 if (empty($extensionName)) {
59 throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
60 }
61 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
62 $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
63
64 $controllers = '';
65 foreach ($controllerActions as $controller => $actionsList) {
66 $controllers .= '
67 ' . $controller . '.actions = ' . $actionsList;
68 if (!empty($nonCacheableControllerActions[$controller])) {
69 $controllers .= '
70 ' . $controller . '.nonCacheableActions = ' . $nonCacheableControllerActions[$controller];
71 }
72 }
73
74 $switchableControllerActions = '
75 switchableControllerActions {' . $controllers . '
76 }';
77
78 reset($controllerActions);
79 $defaultController = key($controllerActions);
80 $controller = '
81 controller = ' . $defaultController;
82 $defaultAction = array_shift(t3lib_div::trimExplode(',', current($controllerActions)));
83 $action = '
84 action = ' . $defaultAction;
85
86 $pluginTemplate = 'plugin.tx_' . strtolower($extensionName) . ' {
87 settings {
88 }
89 persistence {
90 storagePid =
91 classes {
92 }
93 }
94 view {
95 templateRootPath =
96 layoutRootPath =
97 partialRootPath =
98 # with defaultPid you can specify the default page uid of this plugin. If you set this to the string "auto" the target page will be determined automatically. Defaults to an empty string that expects the target page to be the current page.
99 defaultPid =
100 }
101 }';
102 t3lib_extMgm::addTypoScript($extensionName, 'setup', '
103 # Setting ' . $extensionName . ' plugin TypoScript
104 ' . $pluginTemplate);
105
106 $pluginContent = trim('
107 tt_content.list.20.' . $pluginSignature . ' = USER
108 tt_content.list.20.' . $pluginSignature . ' {
109 userFunc = tx_extbase_core_bootstrap->run
110 pluginName = ' . $pluginName . '
111 extensionName = ' . $extensionName . '
112 ' . $controller .
113 $action .
114 $switchableControllerActions . '
115
116 settings =< plugin.tx_' . strtolower($extensionName) . '.settings
117 persistence =< plugin.tx_' . strtolower($extensionName) . '.persistence
118 view =< plugin.tx_' . strtolower($extensionName) . '.view
119 _LOCAL_LANG =< plugin.tx_' . strtolower($extensionName) . '._LOCAL_LANG
120 }');
121
122 t3lib_extMgm::addTypoScript($extensionName, 'setup', '
123 # Setting ' . $extensionName . ' plugin TypoScript
124 ' . $pluginContent, 43);
125 }
126
127 /**
128 * Register an Extbase PlugIn into backend's list of plugins
129 * FOR USE IN ext_tables.php FILES
130 *
131 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
132 * @param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
133 * @param string $pluginTitle is a speaking title of the plugin that will be displayed in the drop down menu in the backend
134 * @return void
135 */
136 static public function registerPlugin($extensionName, $pluginName, $pluginTitle) {
137 if (empty($pluginName)) {
138 throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
139 }
140 if (empty($extensionName)) {
141 throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
142 }
143 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
144 $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
145
146 t3lib_extMgm::addPlugin(array($pluginTitle, $pluginSignature), 'list_type');
147 }
148
149 /**
150 * This method is called from t3lib_loadModules::checkMod and it replaces old conf.php.
151 *
152 * @param string $key The module name
153 * @param string $fullpath Absolute path to module
154 * @param array $MCONF Reference to the array holding the configuration of the module
155 * @param array $MLANG Reference to the array holding the localized module labels
156 * @return array Configuration of the module
157 */
158 public function configureModule($key, $fullpath, array $MCONF = array(), array $MLANG = array()) {
159 $path = preg_replace('/\/[^\/.]+\/\.\.\//', '/', $fullpath); // because 'path/../path' does not work
160 $config = $GLOBALS['TBE_MODULES']['_configuration'][$key]['config'];
161 define('TYPO3_MOD_PATH', $config['extRelPath']);
162
163 // Fill $MCONF
164 $MCONF['name'] = $key;
165 $MCONF['access'] = $config['access'];
166 $MCONF['script'] = '_DISPATCH';
167
168 if (substr($config['icon'], 0, 4) === 'EXT:') {
169 list($extKey, $local) = explode('/', substr($config['icon'], 4), 2);
170 $config['icon'] = t3lib_extMgm::extRelPath($extKey) . $local;
171 }
172
173 // Initialize search for alternative icon:
174 $altIconKey = 'MOD:' . $key . '/' . $config['icon']; // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
175 $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div::resolveBackPath(PATH_typo3.$GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
176
177 // Set icon, either default or alternative:
178 if ($altIconAbsPath && @is_file($altIconAbsPath)) {
179 $tabImage = $altIconAbsPath;
180 } else {
181 // Setting default icon:
182 $tabImage = $config['icon'];
183 }
184
185 // Fill $MLANG
186 $MLANG['default']['ll_ref'] = $config['labels'];
187
188 // Finally, set the icon with correct path:
189 if (substr($tabImage, 0 ,3) === '../') {
190 $MLANG['default']['tabs_images']['tab'] = PATH_site . substr($tabImage, 3);
191 } else {
192 $MLANG['default']['tabs_images']['tab'] = PATH_typo3 . $tabImage;
193 }
194
195 // If LOCAL_LANG references are used for labels of the module:
196 if ($MLANG['default']['ll_ref']) {
197 // Now the 'default' key is loaded with the CURRENT language - not the english translation...
198 $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tablabel');
199 $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tabdescr');
200 $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_tabs_tab');
201 $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $key . '_');
202 } else { // ... otherwise use the old way:
203 $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $key . '_');
204 $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang], $key . '_');
205 }
206
207 // Fill $modconf
208 $modconf['script'] = 'mod.php?M=' . rawurlencode($key);
209 $modconf['name'] = $key;
210
211 // Default tab setting
212 if ($MCONF['defaultMod']) {
213 $modconf['defaultMod'] = $MCONF['defaultMod'];
214 }
215 // Navigation Frame Script (GET params could be added)
216 if ($MCONF['navFrameScript']) {
217 $navFrameScript = explode('?', $MCONF['navFrameScript']);
218 $navFrameScript = $navFrameScript[0];
219 if (file_exists($path . '/' . $navFrameScript)) {
220 $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['navFrameScript']);
221 }
222 }
223
224 // Additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
225 if ($MCONF['navFrameScriptParam']) {
226 $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
227 }
228
229 return $modconf;
230 }
231
232 /**
233 * Registers an Extbase module (main or sub) to the backend interface.
234 * FOR USE IN ext_tables.php FILES
235 *
236 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
237 * @param string $main The main module key, $sub is the submodule key. So $main would be an index in the $TBE_MODULES array and $sub could be an element in the lists there. If $main is not set a blank $extensionName module is created
238 * @param string $sub The submodule key. If $sub is not set a blank $main module is created
239 * @param string $position This can be used to set the position of the $sub module within the list of existing submodules for the main module. $position has this syntax: [cmd]:[submodule-key]. cmd can be "after", "before" or "top" (or blank which is default). If "after"/"before" then submodule will be inserted after/before the existing submodule with [submodule-key] if found. If not found, the bottom of list. If "top" the module is inserted in the top of the submodule list.
240 * @param array $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
241 * @param array $config The configuration options of the module (icon, locallang.xml file)
242 * @return void
243 */
244 static public function registerModule($extensionName, $main = '', $sub = '', $position = '', array $controllerActions, $config = array()) {
245 if (empty($extensionName)) {
246 throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
247 }
248 $extensionKey = $extensionName; // FIXME This will break if the $extensionName is given as BlogExample
249 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
250
251 $path = t3lib_extMgm::extPath($extensionKey, 'Classes/');
252 $relPath = t3lib_extMgm::extRelPath($extensionKey) . 'Classes/';
253
254 if (!is_array($config) || count($config) == 0) {
255 $config['access'] = 'admin';
256 $config['icon'] = '';
257 $config['labels'] = '';
258 $config['extRelPath'] = $relPath;
259 }
260
261 if ((strlen($main) > 0) && !array_key_exists($main, $GLOBALS['TBE_MODULES'])) {
262 $main = $extensionName . self::convertLowerUnderscoreToUpperCamelCase($main);
263 } else {
264 $main = (strlen($main) > 0) ? $main : 'web'; // TODO By now, $main must default to 'web'
265 }
266
267 if ((strlen($sub) > 0)) {
268 //$sub = $extensionName . self::convertLowerUnderscoreToUpperCamelCase($sub);
269 $key = $main . '_' . $sub;
270 } else {
271 $key = $main;
272 }
273
274 $moduleConfig = array(
275 'name' => $key,
276 'extensionKey' => $extensionKey,
277 'extensionName' => $extensionName,
278 'controllerActions' => $controllerActions,
279 'config' => $config,
280 );
281 $GLOBALS['TBE_MODULES']['_configuration'][$key] = $moduleConfig;
282 $GLOBALS['TBE_MODULES']['_configuration'][$key]['configureModuleFunction'] = array('Tx_Extbase_Utility_Extension', 'configureModule');
283
284 t3lib_extMgm::addModule($main, $sub, $position);
285 }
286
287 /**
288 * Returns a given CamelCasedString as an lowercase string with underscores.
289 * Example: Converts BlogExample to blog_example, and minimalValue to minimal_value
290 *
291 * @param string $string
292 * @return mixed
293 * @see t3lib_div::underscoredToLowerCamelCase()
294 * @deprecated since Extbase 1.3.0; will be removed in Extbase 1.5.0
295 */
296 static public function convertCamelCaseToLowerCaseUnderscored($string) {
297 return t3lib_div::camelCaseToLowerCaseUnderscored($string);
298 }
299
300 /**
301 * Returns a given string with underscores as lowerCamelCase.
302 * Example: Converts minimal_value to minimalValue
303 *
304 * @param string $string
305 * @return mixed
306 * @see t3lib_div::underscoredToLowerCamelCase()
307 * @deprecated since Extbase 1.3.0; will be removed in Extbase 1.5.0
308 */
309 static public function convertUnderscoredToLowerCamelCase($string) {
310 return t3lib_div::underscoredToLowerCamelCase($string);
311 }
312
313 /**
314 * Returns a given string with underscores as UpperCamelCase.
315 * Example: Converts blog_example to BlogExample
316 *
317 * @param string $string
318 * @return string
319 * @see t3lib_div::underscoredToUpperCamelCase()
320 * @deprecated since Extbase 1.3.0; will be removed in Extbase 1.5.0
321 */
322 static public function convertLowerUnderscoreToUpperCamelCase($string) {
323 return t3lib_div::underscoredToUpperCamelCase($string);
324 }
325
326 /**
327 * Build the autoload registry for a given extension and place it ext_autoload.php.
328 *
329 * @param string $extensionKey Key of the extension
330 * @param string $extensionPath full path of the extension
331 * @param array $additionalAutoloadClasses additional classes to be added to the autoloader. The key must be the classname all-lowercase, the value must be the entry to be inserted
332 * @return string HTML string which should be outputted
333 */
334 static public function createAutoloadRegistryForExtension($extensionKey, $extensionPath, $additionalAutoloadClasses = array()) {
335 $classNameToFileMapping = array();
336 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionKey)));
337 $errors = self::buildAutoloadRegistryForSinglePath($classNameToFileMapping, $extensionPath . 'Classes/', '.*tslib.*', '$extensionClassesPath . \'|\'');
338 if ($errors) {
339 return $errors;
340 }
341 $globalPrefix = '$extensionClassesPath = t3lib_extMgm::extPath(\'' . $extensionKey . '\') . \'Classes/\';';
342
343 $errors = array();
344 foreach ($classNameToFileMapping as $className => $fileName) {
345 if (!(strpos($className, 'tx_' . strtolower($extensionName)) === 0)) {
346 $errors[] = $className . ' does not start with Tx_' . $extensionName . ' and was not added to the autoloader registry.';
347 unset($classNameToFileMapping[$className]);
348 }
349 }
350 $classNameToFileMapping = array_merge($classNameToFileMapping, $additionalAutoloadClasses);
351 $autoloadFileString = self::generateAutoloadPHPFileData($classNameToFileMapping, $globalPrefix);
352 if (!@file_put_contents($extensionPath . 'ext_autoload.php', $autoloadFileString)) {
353 $errors[] = '<b>' . $extensionPath . 'ext_autoload.php could not be written!</b>';
354 }
355 $errors[] = 'Wrote the following data: <pre>' . htmlspecialchars($autoloadFileString) . '</pre>';
356 return implode('<br />', $errors);
357 }
358
359 /**
360 * Generate autoload PHP file data. Takes an associative array with class name to file mapping, and outputs it as PHP.
361 * Does NOT escape the values in the associative array. Includes the <?php ... ?> syntax and an optional global prefix.
362 *
363 * @param array $classNameToFileMapping class name to file mapping
364 * @param string $globalPrefix Global prefix which is prepended to all code.
365 * @return string The full PHP string
366 */
367 protected function generateAutoloadPHPFileData($classNameToFileMapping, $globalPrefix = '') {
368 $output = '<?php' . PHP_EOL;
369 $output .= '// DO NOT CHANGE THIS FILE! It is automatically generated by Tx_Extbase_Utility_Extension::createAutoloadRegistryForExtension.' . PHP_EOL;
370 $output .= '// This file was generated on ' . date('Y-m-d H:i') . PHP_EOL;
371 $output .= PHP_EOL;
372 $output .= $globalPrefix . PHP_EOL;
373 $output .= 'return array(' . PHP_EOL;
374 foreach ($classNameToFileMapping as $className => $quotedFileName) {
375 $output .= ' \'' . $className . '\' => ' . $quotedFileName . ',' . PHP_EOL;
376 }
377 $output .= ');' . PHP_EOL;
378 $output .= '?>';
379 return $output;
380 }
381
382 /**
383 * Generate the $classNameToFileMapping for a given filePath.
384 *
385 * @param array $classNameToFileMapping (Reference to array) All values are appended to this array.
386 * @param string $path Path which should be crawled
387 * @param string $excludeRegularExpression Exclude regular expression, to exclude certain files from being processed
388 * @param string $valueWrap Wrap for the file name
389 * @return void
390 */
391 static protected function buildAutoloadRegistryForSinglePath(&$classNameToFileMapping, $path, $excludeRegularExpression = '', $valueWrap = '\'|\'') {
392 // if (file_exists($path . 'Classes/')) {
393 // return "<b>This appears to be a new-style extension which has its PHP classes inside the Classes/ subdirectory. It is not needed to generate the autoload registry for these extensions.</b>";
394 // }
395 $extensionFileNames = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(), $path, 'php', FALSE, 99, $excludeRegularExpression), $path);
396
397 foreach ($extensionFileNames as $extensionFileName) {
398 $classNamesInFile = self::extractClassNames($path . $extensionFileName);
399 if (!count($classNamesInFile)) continue;
400 foreach ($classNamesInFile as $className) {
401 $classNameToFileMapping[strtolower($className)] = str_replace('|', $extensionFileName, $valueWrap);
402 }
403 }
404 }
405
406 /**
407 * Extracts class names from the given file.
408 *
409 * @param string $filePath File path (absolute)
410 * @return array Class names
411 */
412 static protected function extractClassNames($filePath) {
413 $fileContent = php_strip_whitespace($filePath);
414 $classNames = array();
415 if (FALSE) {
416 $tokens = token_get_all($fileContent);
417 while(1) {
418 // look for "class" or "interface"
419 $token = self::findToken($tokens, array(T_ABSTRACT, T_CLASS, T_INTERFACE));
420 // fetch "class" token if "abstract" was found
421 if ($token === 'abstract') {
422 $token = self::findToken($tokens, array(T_CLASS));
423 }
424 if ($token === false) {
425 // end of file
426 break;
427 }
428 // look for the name (a string) skipping only whitespace and comments
429 $token = self::findToken($tokens, array(T_STRING), array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT));
430 if ($token === false) {
431 // unexpected end of file or token: remove found names because of parse error
432 t3lib_div::sysLog('Parse error in "' . $filePath. '".', 'Core', 2);
433 $classNames = array();
434 break;
435 }
436 $token = t3lib_div::strtolower($token);
437 // exclude XLASS classes
438 if (strncmp($token, 'ux_', 3)) {
439 $classNames[] = $token;
440 }
441 }
442 } else {
443 // TODO: parse PHP - skip coments and strings, apply regexp only on the remaining PHP code
444 $matches = array();
445 preg_match_all('/^[ \t]*(?:(?:abstract|final)?[ \t]*(?:class|interface))[ \t\n\r]+([a-zA-Z][a-zA-Z_0-9]*)/mS', $fileContent, $matches);
446 $classNames = array_map('t3lib_div::strtolower', $matches[1]);
447 }
448 return $classNames;
449 }
450
451 /**
452 * Find tokens in the tokenList
453 *
454 * @param array $tokenList list of tokens as returned by token_get_all()
455 * @param array $wantedToken the tokens to be found
456 * @param array $intermediateTokens optional: list of tokens that are allowed to skip when looking for the wanted token
457 * @return mixed
458 */
459 static protected function findToken(array &$tokenList, array $wantedTokens, array $intermediateTokens = array()) {
460 $skipAllTokens = count($intermediateTokens) ? false : true;
461
462 $returnValue = false;
463 // Iterate with while since we need the current array position:
464 foreach ($tokenList as $token) {
465 // parse token (see http://www.php.net/manual/en/function.token-get-all.php for format of token list)
466 if (is_array($token)) {
467 list($id, $text) = $token;
468 } else {
469 $id = $text = $token;
470 }
471 if (in_array($id, $wantedTokens)) {
472 $returnValue = $text;
473 break;
474 }
475 // look for another token
476 if ($skipAllTokens || in_array($id, $intermediateTokens)) {
477 continue;
478 }
479 break;
480 }
481 return $returnValue;
482 }
483
484 /**
485 * Determines the plugin namespace of the specified plugin (defaults to "tx_[extensionname]_[pluginname]")
486 * If plugin.tx_$pluginSignature.view.pluginNamespace is set, this value is returned
487 * If pluginNamespace is not specified "tx_[extensionname]_[pluginname]" is returned.
488 *
489 * @param string $extensionName name of the extension to retrieve the namespace for
490 * @param string $pluginName name of the plugin to retrieve the namespace for
491 * @return string plugin namespace
492 */
493 static public function getPluginNamespace($extensionName, $pluginName) {
494 $pluginSignature = strtolower($extensionName . '_' . $pluginName);
495 $defaultPluginNamespace = 'tx_' . $pluginSignature;
496 $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
497 $configurationManager = $objectManager->get('Tx_Extbase_Configuration_ConfigurationManagerInterface');
498 if (!isset($configurationManager) || !isset($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']) || !is_array($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.'])) {
499 return $defaultPluginNamespace;
500 }
501 $frameworkConfiguration = $configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
502 if (!isset($frameworkConfiguration['view']['pluginNamespace']) || empty($frameworkConfiguration['view']['pluginNamespace'])) {
503 return $defaultPluginNamespace;
504 }
505 return $frameworkConfiguration['view']['pluginNamespace'];
506 }
507
508 /**
509 * Iterates through the global TypoScript configuration and returns the name of the plugin
510 * that matches specified extensionName, controllerName and actionName.
511 * If no matching plugin was found, NULL is returned.
512 * If more than one plugin matches, an Exception will be thrown
513 *
514 * @param string $extensionName name of the target extension (UpperCamelCase)
515 * @param string $controllerName name of the target controller (UpperCamelCase)
516 * @param string $actionName name of the target action (lowerCamelCase)
517 * @return string name of the target plugin (UpperCamelCase) or NULL if no matching plugin configuration was found
518 */
519 static public function getPluginNameByAction($extensionName, $controllerName, $actionName) {
520 if (!isset($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']) || !is_array($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.'])) {
521 return NULL;
522 }
523 $pluginNames = array();
524 foreach($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.'] as $pluginConfiguration) {
525 if (!is_array($pluginConfiguration) || !isset($pluginConfiguration['switchableControllerActions.']) || !isset($pluginConfiguration['extensionName'])) {
526 continue;
527 }
528 if (strtolower($extensionName) !== strtolower($pluginConfiguration['extensionName'])) {
529 continue;
530 }
531 foreach($pluginConfiguration['switchableControllerActions.'] as $controller => $switchableControllerActions) {
532 if (strtolower(rtrim($controller, '.')) !== strtolower($controllerName)) {
533 continue;
534 }
535 $actions = t3lib_div::trimExplode(',', $switchableControllerActions['actions']);
536 if (in_array($actionName, $actions)) {
537 $pluginNames[] = $pluginConfiguration['pluginName'];
538 }
539 }
540 }
541 if (count($pluginNames) > 1) {
542 throw new Tx_Extbase_Exception('There is more than one plugin that can handle this request (Extension: "' . $extensionName . '", Controller: "' . $controllerName . '", action: "' . $actionName . '"). Please specify "pluginName" argument' , 1280825466);
543 }
544 return count($pluginNames) > 0 ? $pluginNames[0] : NULL;
545 }
546
547 /**
548 * Determines the target page of the specified plugin.
549 * If plugin.tx_$pluginSignature.view.defaultPid is set, this value is used as target page id
550 * If defaultPid is set to "auto", a the target pid is determined by loading the tt_content record that contains this plugin
551 * If the page could not be determined, NULL is returned
552 * If defaultPid is "auto" and more than one page contains the specified plugin, an Exception is thrown
553 *
554 * @param string $extensionName name of the extension to retrieve the target PID for
555 * @param string $pluginName name of the plugin to retrieve the target PID for
556 * @return integer uid of the target page or NULL if target page could not be determined
557 */
558 static public function getTargetPidByPlugin($extensionName, $pluginName) {
559 $pluginSignature = strtolower($extensionName . '_' . $pluginName);
560 $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
561 $configurationManager = $objectManager->get('Tx_Extbase_Configuration_ConfigurationManagerInterface');
562 if (!isset($configurationManager) || !isset($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']) || !is_array($GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.'])) {
563 return NULL;
564 }
565 $frameworkConfiguration = $configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
566 if (!isset($frameworkConfiguration['view']['defaultPid']) || empty($frameworkConfiguration['view']['defaultPid'])) {
567 return NULL;
568 }
569 if ($frameworkConfiguration['view']['defaultPid'] === 'auto') {
570 $pages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
571 'pid',
572 'tt_content',
573 'list_type=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($pluginSignature, 'tt_content') . $GLOBALS['TSFE']->sys_page->enableFields('tt_content'),
574 '',
575 '',
576 2
577 );
578 if (count($pages) > 1) {
579 throw new Tx_Extbase_Exception('There is more than one "' . $pluginSignature . '" plugin in the current page tree. Please remove one plugin or set the TypoScript configuration "plugin.tx_' . $pluginSignature . '.view.defaultPid" to a fixed page id' , 1280773643);
580 }
581 return count($pages) > 0 ? $pages[0]['pid'] : NULL;
582 }
583 return (integer)$frameworkConfiguration['view']['defaultPid'];
584 }
585 }
586
587 ?>