[BUGFIX] Followup Fluid Template Fallback paths
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / ExtensionUtility.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * Utilities to manage plugins and modules of an extension. Also useful to auto-generate the autoloader registry
32 * file ext_autoload.php.
33 */
34 class ExtensionUtility {
35
36 const PLUGIN_TYPE_PLUGIN = 'list_type';
37 const PLUGIN_TYPE_CONTENT_ELEMENT = 'CType';
38
39 /**
40 * Add auto-generated TypoScript to configure the Extbase Dispatcher.
41 *
42 * When adding a frontend plugin you will have to add both an entry to the TCA definition
43 * of tt_content table AND to the TypoScript template which must initiate the rendering.
44 * Since the static template with uid 43 is the "content.default" and practically always
45 * used for rendering the content elements it's very useful to have this function automatically
46 * adding the necessary TypoScript for calling the appropriate controller and action of your plugin.
47 * It will also work for the extension "css_styled_content"
48 * FOR USE IN ext_localconf.php FILES
49 * Usage: 2
50 *
51 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
52 * @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!)
53 * @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)
54 * @param array $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
55 * @param string $pluginType either \TYPO3\CMS\Extbase\Utility\ExtensionUtility::TYPE_PLUGIN (default) or \TYPO3\CMS\Extbase\Utility\ExtensionUtility::TYPE_CONTENT_ELEMENT
56 * @throws \InvalidArgumentException
57 * @return void
58 */
59 static public function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = array(), $pluginType = self::PLUGIN_TYPE_PLUGIN) {
60 if (empty($pluginName)) {
61 throw new \InvalidArgumentException('The plugin name must not be empty', 1239891987);
62 }
63 if (empty($extensionName)) {
64 throw new \InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
65 }
66 // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
67 $vendorName = NULL;
68 $delimiterPosition = strrpos($extensionName, '.');
69 if ($delimiterPosition !== FALSE) {
70 $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
71 $extensionName = substr($extensionName, $delimiterPosition + 1);
72 }
73 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
74 $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
75 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName])) {
76 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName] = array();
77 }
78 foreach ($controllerActions as $controllerName => $actionsList) {
79 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName] = array('actions' => \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $actionsList));
80 if (!empty($nonCacheableControllerActions[$controllerName])) {
81 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName]['nonCacheableActions'] = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $nonCacheableControllerActions[$controllerName]);
82 }
83 }
84 $pluginTemplate = 'plugin.tx_' . strtolower($extensionName) . ' {
85 settings {
86 }
87 persistence {
88 storagePid =
89 classes {
90 }
91 }
92 view {
93 templateRootPaths {
94 #example: fooKey = EXT:bar/foo
95 }
96 layoutRootPaths {
97 #example: fooKey = EXT:bar/foo
98 }
99 partialRootPaths {
100 #example: fooKey = EXT:bar/foo
101 }
102 # 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.
103 defaultPid =
104 }
105 }';
106 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript($extensionName, 'setup', '
107 # Setting ' . $extensionName . ' plugin TypoScript
108 ' . $pluginTemplate);
109 switch ($pluginType) {
110 case self::PLUGIN_TYPE_PLUGIN:
111 $pluginContent = trim('
112 tt_content.list.20.' . $pluginSignature . ' = USER
113 tt_content.list.20.' . $pluginSignature . ' {
114 userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
115 extensionName = ' . $extensionName . '
116 pluginName = ' . $pluginName . (NULL !== $vendorName ? ("\n\t" . 'vendorName = ' . $vendorName) : '') . '
117 }');
118 break;
119 case self::PLUGIN_TYPE_CONTENT_ELEMENT:
120 $pluginContent = trim('
121 tt_content.' . $pluginSignature . ' = COA
122 tt_content.' . $pluginSignature . ' {
123 10 = < lib.stdheader
124 20 = USER
125 20 {
126 userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
127 extensionName = ' . $extensionName . '
128 pluginName = ' . $pluginName . (NULL !== $vendorName ? ("\n\t\t" . 'vendorName = ' . $vendorName) : '') . '
129 }
130 }');
131 break;
132 default:
133 throw new \InvalidArgumentException('The pluginType "' . $pluginType . '" is not suported', 1289858856);
134 }
135 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType'] = $pluginType;
136 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript($extensionName, 'setup', '
137 # Setting ' . $extensionName . ' plugin TypoScript
138 ' . $pluginContent, 43);
139 }
140
141 /**
142 * Register an Extbase PlugIn into backend's list of plugins
143 * FOR USE IN ext_tables.php FILES
144 *
145 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
146 * @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!)
147 * @param string $pluginTitle is a speaking title of the plugin that will be displayed in the drop down menu in the backend
148 * @param string $pluginIconPathAndFilename is a path to an icon file (relative to TYPO3_mainDir), that will be displayed in the drop down menu in the backend (optional)
149 * @throws \InvalidArgumentException
150 * @return void
151 */
152 static public function registerPlugin($extensionName, $pluginName, $pluginTitle, $pluginIconPathAndFilename = NULL) {
153 if (empty($pluginName)) {
154 throw new \InvalidArgumentException('The plugin name must not be empty', 1239891987);
155 }
156 if (empty($extensionName)) {
157 throw new \InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
158 }
159 $delimiterPosition = strrpos($extensionName, '.');
160 if ($delimiterPosition !== FALSE) {
161 $extensionName = substr($extensionName, $delimiterPosition + 1);
162 }
163 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
164 $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
165 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(array($pluginTitle, $pluginSignature, $pluginIconPathAndFilename), $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType']);
166 }
167
168 /**
169 * This method is called from \TYPO3\CMS\Backend\Module\ModuleLoader::checkMod
170 * and it replaces old conf.php.
171 *
172 * @param string $moduleSignature The module name
173 * @param string $modulePath Absolute path to module (not used by Extbase currently)
174 * @return array Configuration of the module
175 */
176 static public function configureModule($moduleSignature, $modulePath) {
177 $moduleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature];
178 $iconPathAndFilename = $moduleConfiguration['icon'];
179 if (substr($iconPathAndFilename, 0, 4) === 'EXT:') {
180 list($extensionKey, $relativePath) = explode('/', substr($iconPathAndFilename, 4), 2);
181 $iconPathAndFilename = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($extensionKey) . $relativePath;
182 }
183 // TODO: skin support
184 $moduleLabels = array(
185 'tabs_images' => array(
186 'tab' => $iconPathAndFilename
187 ),
188 'labels' => array(
189 'tablabel' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_labels_tablabel'),
190 'tabdescr' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_labels_tabdescr')
191 ),
192 'tabs' => array(
193 'tab' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_tabs_tab')
194 )
195 );
196 $GLOBALS['LANG']->addModuleLabels($moduleLabels, $moduleSignature . '_');
197 return $moduleConfiguration;
198 }
199
200 /**
201 * Registers an Extbase module (main or sub) to the backend interface.
202 * FOR USE IN ext_tables.php FILES
203 *
204 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
205 * @param string $mainModuleName The main module key. So $main would be an index in the $TBE_MODULES array and $sub could be an element in the lists there. If $subModuleName is not set a blank $extensionName module is created
206 * @param string $subModuleName The submodule key.
207 * @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.
208 * @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)
209 * @param array $moduleConfiguration The configuration options of the module (icon, locallang.xlf file)
210 * @throws \InvalidArgumentException
211 * @return void
212 */
213 static public function registerModule($extensionName, $mainModuleName = '', $subModuleName = '', $position = '', array $controllerActions, array $moduleConfiguration = array()) {
214 if (empty($extensionName)) {
215 throw new \InvalidArgumentException('The extension name must not be empty', 1239891989);
216 }
217 // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
218 $vendorName = NULL;
219 if (FALSE !== $delimiterPosition = strrpos($extensionName, '.')) {
220 $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
221 $extensionName = substr($extensionName, $delimiterPosition + 1);
222 }
223 $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName);
224 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
225 $defaultModuleConfiguration = array(
226 'access' => 'admin',
227 'icon' => 'EXT:extbase/ext_icon.gif',
228 'labels' => '',
229 'extRelPath' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($extensionKey) . 'Classes/'
230 );
231 if (strlen($mainModuleName) > 0 && !array_key_exists($mainModuleName, $GLOBALS['TBE_MODULES'])) {
232 $mainModuleName = $extensionName . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($mainModuleName);
233 } else {
234 $mainModuleName = strlen($mainModuleName) > 0 ? $mainModuleName : 'web';
235 }
236 // add mandatory parameter to use new pagetree
237 if ($mainModuleName === 'web') {
238 $defaultModuleConfiguration['navigationComponentId'] = 'typo3-pagetree';
239 }
240 $moduleConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($defaultModuleConfiguration, $moduleConfiguration);
241 $moduleSignature = $mainModuleName;
242 if (strlen($subModuleName) > 0) {
243 $subModuleName = $extensionName . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($subModuleName);
244 $moduleSignature .= '_' . $subModuleName;
245 }
246 $moduleConfiguration['name'] = $moduleSignature;
247 $moduleConfiguration['script'] = 'mod.php?M=' . rawurlencode($moduleSignature);
248 if (NULL !== $vendorName) {
249 $moduleConfiguration['vendorName'] = $vendorName;
250 }
251 $moduleConfiguration['extensionName'] = $extensionName;
252 $moduleConfiguration['configureModuleFunction'] = array('TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility', 'configureModule');
253 $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature] = $moduleConfiguration;
254 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature])) {
255 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature] = array();
256 }
257 foreach ($controllerActions as $controllerName => $actions) {
258 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature]['controllers'][$controllerName] = array(
259 'actions' => \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $actions)
260 );
261 }
262 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addModule($mainModuleName, $subModuleName, $position);
263 }
264
265 /**
266 * Register a type converter by class name.
267 *
268 * @param string $typeConverterClassName
269 * @return void
270 * @api
271 */
272 static public function registerTypeConverter($typeConverterClassName) {
273 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'])) {
274 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'] = array();
275 }
276 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'][] = $typeConverterClassName;
277 }
278 }