[CLEANUP] Replace strlen() with === for zero length check
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / ExtensionUtility.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Utilities to manage plugins and modules of an extension. Also useful to auto-generate the autoloader registry
19 * file ext_autoload.php.
20 */
21 class ExtensionUtility {
22
23 const PLUGIN_TYPE_PLUGIN = 'list_type';
24 const PLUGIN_TYPE_CONTENT_ELEMENT = 'CType';
25
26 /**
27 * Add auto-generated TypoScript to configure the Extbase Dispatcher.
28 *
29 * When adding a frontend plugin you will have to add both an entry to the TCA definition
30 * of tt_content table AND to the TypoScript template which must initiate the rendering.
31 * Since the static template with uid 43 is the "content.default" and practically always
32 * used for rendering the content elements it's very useful to have this function automatically
33 * adding the necessary TypoScript for calling the appropriate controller and action of your plugin.
34 * It will also work for the extension "css_styled_content"
35 * FOR USE IN ext_localconf.php FILES
36 * Usage: 2
37 *
38 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
39 * @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!)
40 * @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)
41 * @param array $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
42 * @param string $pluginType either \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_PLUGIN (default) or \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
43 * @throws \InvalidArgumentException
44 * @return void
45 */
46 static public function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = array(), $pluginType = self::PLUGIN_TYPE_PLUGIN) {
47 if (empty($pluginName)) {
48 throw new \InvalidArgumentException('The plugin name must not be empty', 1239891987);
49 }
50 if (empty($extensionName)) {
51 throw new \InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
52 }
53 // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
54 $vendorName = NULL;
55 $delimiterPosition = strrpos($extensionName, '.');
56 if ($delimiterPosition !== FALSE) {
57 $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
58 $extensionName = substr($extensionName, $delimiterPosition + 1);
59 }
60 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
61
62 $pluginSignature = strtolower($extensionName . '_' . $pluginName);
63 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName])) {
64 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName] = array();
65 }
66 foreach ($controllerActions as $controllerName => $actionsList) {
67 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName] = array('actions' => \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $actionsList));
68 if (!empty($nonCacheableControllerActions[$controllerName])) {
69 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName]['nonCacheableActions'] = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $nonCacheableControllerActions[$controllerName]);
70 }
71 }
72
73 switch ($pluginType) {
74 case self::PLUGIN_TYPE_PLUGIN:
75 $pluginContent = trim('
76 tt_content.list.20.' . $pluginSignature . ' = USER
77 tt_content.list.20.' . $pluginSignature . ' {
78 userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
79 extensionName = ' . $extensionName . '
80 pluginName = ' . $pluginName . (NULL !== $vendorName ? ("\n\t" . 'vendorName = ' . $vendorName) : '') . '
81 }');
82 break;
83 case self::PLUGIN_TYPE_CONTENT_ELEMENT:
84 $pluginContent = trim('
85 tt_content.' . $pluginSignature . ' = COA
86 tt_content.' . $pluginSignature . ' {
87 10 = < lib.stdheader
88 20 = USER
89 20 {
90 userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
91 extensionName = ' . $extensionName . '
92 pluginName = ' . $pluginName . (NULL !== $vendorName ? ("\n\t\t" . 'vendorName = ' . $vendorName) : '') . '
93 }
94 }');
95 break;
96 default:
97 throw new \InvalidArgumentException('The pluginType "' . $pluginType . '" is not suported', 1289858856);
98 }
99 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType'] = $pluginType;
100 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript($extensionName, 'setup', '
101 # Setting ' . $extensionName . ' plugin TypoScript
102 ' . $pluginContent, 43);
103 }
104
105 /**
106 * Register an Extbase PlugIn into backend's list of plugins
107 * FOR USE IN ext_tables.php FILES
108 *
109 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
110 * @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!)
111 * @param string $pluginTitle is a speaking title of the plugin that will be displayed in the drop down menu in the backend
112 * @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)
113 * @throws \InvalidArgumentException
114 * @return void
115 */
116 static public function registerPlugin($extensionName, $pluginName, $pluginTitle, $pluginIconPathAndFilename = NULL) {
117 if (empty($pluginName)) {
118 throw new \InvalidArgumentException('The plugin name must not be empty', 1239891988);
119 }
120 if (empty($extensionName)) {
121 throw new \InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891991);
122 }
123 $delimiterPosition = strrpos($extensionName, '.');
124 if ($delimiterPosition !== FALSE) {
125 $extensionName = substr($extensionName, $delimiterPosition + 1);
126 }
127 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
128 $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
129
130 // At this point $extensionName is normalized, no matter which format the method was feeded with.
131 // Calculate the original extensionKey from this again.
132 $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName);
133
134 // pluginType is usually defined by configurePlugin() in the global array. Use this or fall back to default "list_type".
135 $pluginType = isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType'])
136 ? $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType']
137 : 'list_type';
138
139 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
140 array($pluginTitle, $pluginSignature, $pluginIconPathAndFilename),
141 $pluginType,
142 $extensionKey
143 );
144 }
145
146 /**
147 * This method is called from \TYPO3\CMS\Backend\Module\ModuleLoader::checkMod
148 * and it replaces old conf.php.
149 *
150 * @param string $moduleSignature The module name
151 * @param string $modulePath Absolute path to module (not used by Extbase currently)
152 * @return array Configuration of the module
153 */
154 static public function configureModule($moduleSignature, $modulePath) {
155 $moduleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature];
156 $iconPathAndFilename = $moduleConfiguration['icon'];
157 if (substr($iconPathAndFilename, 0, 4) === 'EXT:') {
158 list($extensionKey, $relativePath) = explode('/', substr($iconPathAndFilename, 4), 2);
159 $iconPathAndFilename = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($extensionKey) . $relativePath;
160 }
161 // @todo skin support
162 $moduleLabels = array(
163 'tabs_images' => array(
164 'tab' => $iconPathAndFilename
165 ),
166 'labels' => array(
167 'tablabel' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_labels_tablabel'),
168 'tabdescr' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_labels_tabdescr')
169 ),
170 'tabs' => array(
171 'tab' => $GLOBALS['LANG']->sL($moduleConfiguration['labels'] . ':mlang_tabs_tab')
172 )
173 );
174 $GLOBALS['LANG']->addModuleLabels($moduleLabels, $moduleSignature . '_');
175 return $moduleConfiguration;
176 }
177
178 /**
179 * Registers an Extbase module (main or sub) to the backend interface.
180 * FOR USE IN ext_tables.php FILES
181 *
182 * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
183 * @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
184 * @param string $subModuleName The submodule key.
185 * @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.
186 * @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)
187 * @param array $moduleConfiguration The configuration options of the module (icon, locallang.xlf file)
188 * @throws \InvalidArgumentException
189 * @return void
190 */
191 static public function registerModule($extensionName, $mainModuleName = '', $subModuleName = '', $position = '', array $controllerActions = array(), array $moduleConfiguration = array()) {
192 if (empty($extensionName)) {
193 throw new \InvalidArgumentException('The extension name must not be empty', 1239891990);
194 }
195 // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
196 $vendorName = NULL;
197 if (FALSE !== $delimiterPosition = strrpos($extensionName, '.')) {
198 $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
199 $extensionName = substr($extensionName, $delimiterPosition + 1);
200 }
201 $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName);
202 $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
203 $defaultModuleConfiguration = array(
204 'access' => 'admin',
205 'icon' => 'EXT:extbase/ext_icon.gif',
206 'labels' => '',
207 'extRelPath' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($extensionKey) . 'Classes/'
208 );
209 if ($mainModuleName !== '' && !array_key_exists($mainModuleName, $GLOBALS['TBE_MODULES'])) {
210 $mainModuleName = $extensionName . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($mainModuleName);
211 } else {
212 $mainModuleName = $mainModuleName !== '' ? $mainModuleName : 'web';
213 }
214 // add mandatory parameter to use new pagetree
215 if ($mainModuleName === 'web') {
216 $defaultModuleConfiguration['navigationComponentId'] = 'typo3-pagetree';
217 }
218 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($defaultModuleConfiguration, $moduleConfiguration);
219 $moduleConfiguration = $defaultModuleConfiguration;
220 $moduleSignature = $mainModuleName;
221 if ($subModuleName !== '') {
222 $subModuleName = $extensionName . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($subModuleName);
223 $moduleSignature .= '_' . $subModuleName;
224 }
225 $moduleConfiguration['name'] = $moduleSignature;
226 if (NULL !== $vendorName) {
227 $moduleConfiguration['vendorName'] = $vendorName;
228 }
229 $moduleConfiguration['extensionName'] = $extensionName;
230 $moduleConfiguration['configureModuleFunction'] = array(\TYPO3\CMS\Extbase\Utility\ExtensionUtility::class, 'configureModule');
231 $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature] = $moduleConfiguration;
232 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature])) {
233 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature] = array();
234 }
235 foreach ($controllerActions as $controllerName => $actions) {
236 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature]['controllers'][$controllerName] = array(
237 'actions' => \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $actions)
238 );
239 }
240 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addModule($mainModuleName, $subModuleName, $position);
241 }
242
243 /**
244 * Register a type converter by class name.
245 *
246 * @param string $typeConverterClassName
247 * @return void
248 * @api
249 */
250 static public function registerTypeConverter($typeConverterClassName) {
251 if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'])) {
252 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'] = array();
253 }
254 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'][] = $typeConverterClassName;
255 }
256
257 }