‪TYPO3CMS  10.4
ExtensionUtility.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
24 
30 {
31  const ‪PLUGIN_TYPE_PLUGIN = 'list_type';
33 
51  public static function ‪configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = [], $pluginType = self::PLUGIN_TYPE_PLUGIN)
52  {
53  ‪self::checkPluginNameFormat($pluginName);
54  ‪self::checkExtensionNameFormat($extensionName);
55 
56  // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
57  $vendorName = null;
58  $delimiterPosition = strrpos($extensionName, '.');
59  if ($delimiterPosition !== false) {
60  $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
61  trigger_error(
62  'Calling method ' . __METHOD__ . ' with argument $extensionName ("' . $extensionName . '") containing the vendor name ("' . $vendorName . '") is deprecated and will stop working in TYPO3 11.0.',
63  E_USER_DEPRECATED
64  );
65  $extensionName = substr($extensionName, $delimiterPosition + 1);
66 
67  if (!empty($vendorName)) {
68  ‪self::checkVendorNameFormat($vendorName, $extensionName);
69  }
70  }
71  $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
72 
73  $pluginSignature = strtolower($extensionName . '_' . $pluginName);
74  if (!is_array(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName] ?? false)) {
75  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName] = [];
76  }
77  foreach ($controllerActions as $controllerClassName => $actionsList) {
78  if (class_exists($controllerClassName)) {
79  $controllerAlias = ‪self::resolveControllerAliasFromControllerClassName($controllerClassName);
80  $vendorName = ‪self::resolveVendorFromExtensionAndControllerClassName($extensionName, $controllerClassName);
81  if (!empty($vendorName)) {
82  ‪self::checkVendorNameFormat($vendorName, $extensionName);
83  }
84  } else {
85  trigger_error(
86  'Calling ' . __METHOD__ . ' for extension ("' . $extensionName . '") and plugin ("' . $pluginName . '") with controller aliases in argument $controllerActions is deprecated and will stop working in TYPO3 11.0.',
87  E_USER_DEPRECATED
88  );
89  $controllerAlias = $controllerClassName;
90  $controllerClassName = static::getControllerClassName((string)$vendorName, $extensionName, '', $controllerAlias);
91  }
92 
93  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerClassName] = [
94  'className' => $controllerClassName,
95  'alias' => $controllerAlias,
96  'actions' => ‪GeneralUtility::trimExplode(',', $actionsList)
97  ];
98 
99  if (isset($nonCacheableControllerActions[$controllerAlias]) && !empty($nonCacheableControllerActions[$controllerAlias])) {
100  trigger_error(
101  'Calling ' . __METHOD__ . ' for extension ("' . $extensionName . '") and plugin ("' . $pluginName . '") with controller aliases in argument $nonCacheableControllerActions is deprecated and will stop working in TYPO3 11.0.',
102  E_USER_DEPRECATED
103  );
104  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerClassName]['nonCacheableActions'] = ‪GeneralUtility::trimExplode(
105  ',',
106  $nonCacheableControllerActions[$controllerAlias]
107  );
108  }
109 
110  if (isset($nonCacheableControllerActions[$controllerClassName]) && !empty($nonCacheableControllerActions[$controllerClassName])) {
111  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerClassName]['nonCacheableActions'] = ‪GeneralUtility::trimExplode(
112  ',',
113  $nonCacheableControllerActions[$controllerClassName]
114  );
115  }
116  }
117 
118  switch ($pluginType) {
120  $pluginContent = trim('
121 tt_content.list.20.' . $pluginSignature . ' = USER
122 tt_content.list.20.' . $pluginSignature . ' {
123  userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
124  extensionName = ' . $extensionName . '
125  pluginName = ' . $pluginName . '
126 }');
127  break;
129  $pluginContent = trim('
130 tt_content.' . $pluginSignature . ' =< lib.contentElement
131 tt_content.' . $pluginSignature . ' {
132  templateName = Generic
133  20 = USER
134  20 {
135  userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
136  extensionName = ' . $extensionName . '
137  pluginName = ' . $pluginName . '
138  }
139 }');
140  break;
141  default:
142  throw new \InvalidArgumentException('The pluginType "' . $pluginType . '" is not supported', 1289858856);
143  }
144  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType'] = $pluginType;
145  ‪ExtensionManagementUtility::addTypoScript($extensionName, 'setup', '
146 # Setting ' . $extensionName . ' plugin TypoScript
147 ' . $pluginContent, 'defaultContentRendering');
148  }
149 
161  public static function ‪registerPlugin($extensionName, $pluginName, $pluginTitle, $pluginIcon = null, $group = 'default')
162  {
163  ‪self::checkPluginNameFormat($pluginName);
164  ‪self::checkExtensionNameFormat($extensionName);
165 
166  $delimiterPosition = strrpos($extensionName, '.');
167  if ($delimiterPosition !== false) {
168  $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
169  trigger_error(
170  'Calling method ' . __METHOD__ . ' with argument $extensionName ("' . $extensionName . '") containing the vendor name ("' . $vendorName . '") is deprecated and will stop working in TYPO3 11.0.',
171  E_USER_DEPRECATED
172  );
173  $extensionName = substr($extensionName, $delimiterPosition + 1);
174  }
175  $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
176  $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
177 
178  // At this point $extensionName is normalized, no matter which format the method was fed with.
179  // Calculate the original extensionKey from this again.
180  $extensionKey = ‪GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName);
181 
182  // pluginType is usually defined by configurePlugin() in the global array. Use this or fall back to default "list_type".
183  $pluginType = ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['pluginType'] ?? 'list_type';
184 
185  $itemArray = [$pluginTitle, $pluginSignature, $pluginIcon];
186  if ($group) {
187  $itemArray[3] = $group;
188  }
190  $itemArray,
191  $pluginType,
192  $extensionKey
193  );
194  }
195 
208  public static function ‪registerModule($extensionName, $mainModuleName = '', $subModuleName = '', $position = '', array $controllerActions = [], array $moduleConfiguration = [])
209  {
210  ‪self::checkExtensionNameFormat($extensionName);
211 
212  // Check if vendor name is prepended to extensionName in the format {vendorName}.{extensionName}
213  $vendorName = '';
214  if (false !== $delimiterPosition = strrpos($extensionName, '.')) {
215  trigger_error(
216  'Calling method ' . __METHOD__ . ' with argument $extensionName containing the vendor name is deprecated and will stop working in TYPO3 11.0.',
217  E_USER_DEPRECATED
218  );
219  $vendorName = str_replace('.', '\\', substr($extensionName, 0, $delimiterPosition));
220  $extensionName = substr($extensionName, $delimiterPosition + 1);
221 
222  if (!empty($vendorName)) {
223  ‪self::checkVendorNameFormat($vendorName, $extensionName);
224  }
225  }
226 
227  $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
228  $defaultModuleConfiguration = [
229  'access' => 'admin',
230  'icon' => 'EXT:extbase/Resources/Public/Icons/Extension.png',
231  'labels' => ''
232  ];
233  if ($mainModuleName !== '' && !array_key_exists($mainModuleName, ‪$GLOBALS['TBE_MODULES'])) {
234  $mainModuleName = $extensionName . ‪GeneralUtility::underscoredToUpperCamelCase($mainModuleName);
235  } else {
236  $mainModuleName = $mainModuleName !== '' ? $mainModuleName : 'web';
237  }
238  // add mandatory parameter to use new pagetree
239  if ($mainModuleName === 'web') {
240  $defaultModuleConfiguration['navigationComponentId'] = 'TYPO3/CMS/Backend/PageTree/PageTreeElement';
241  }
242  ‪ArrayUtility::mergeRecursiveWithOverrule($defaultModuleConfiguration, $moduleConfiguration);
243  $moduleConfiguration = $defaultModuleConfiguration;
244  $moduleSignature = $mainModuleName;
245  if ($subModuleName !== '') {
246  $subModuleName = $extensionName . ‪GeneralUtility::underscoredToUpperCamelCase($subModuleName);
247  $moduleSignature .= '_' . $subModuleName;
248  }
249  $moduleConfiguration['name'] = $moduleSignature;
250  $moduleConfiguration['extensionName'] = $extensionName;
251  $moduleConfiguration['routeTarget'] = Bootstrap::class . '::handleBackendRequest';
252  if (!is_array(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature] ?? false)) {
253  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature] = [];
254  }
255  foreach ($controllerActions as $controllerClassName => $actionsList) {
256  if (class_exists($controllerClassName)) {
257  $controllerAlias = ‪self::resolveControllerAliasFromControllerClassName($controllerClassName);
258  $vendorName = ‪self::resolveVendorFromExtensionAndControllerClassName($extensionName, $controllerClassName);
259  if (!empty($vendorName)) {
260  ‪self::checkVendorNameFormat($vendorName, $extensionName);
261  }
262  } else {
263  trigger_error(
264  'Calling ' . __METHOD__ . ' with controller aliases is deprecated and will stop working in TYPO3 11.0.',
265  E_USER_DEPRECATED
266  );
267  $controllerAlias = $controllerClassName;
268  $controllerClassName = static::getControllerClassName($vendorName, $extensionName, '', $controllerAlias);
269  }
270 
271  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature]['controllers'][$controllerClassName] = [
272  'className' => $controllerClassName,
273  'alias' => $controllerAlias,
274  'actions' => ‪GeneralUtility::trimExplode(',', $actionsList)
275  ];
276  }
277  ‪ExtensionManagementUtility::addModule($mainModuleName, $subModuleName, $position, null, $moduleConfiguration);
278  }
279 
291  public static function ‪getControllerClassName(
292  string $vendor,
293  string $extensionKey,
294  string $subPackageKey,
295  string $controllerAlias
296  ): string {
297  $objectName = str_replace(
298  [
299  '@extension',
300  '@subpackage',
301  '@controller',
302  '@vendor',
303  '\\\\'
304  ],
305  [
306  $extensionKey,
307  $subPackageKey,
308  $controllerAlias,
309  $vendor,
310  '\\'
311  ],
312  '@vendor\@extension\@subpackage\Controller\@controllerController'
313  );
314 
315  if ($objectName === false) {
316  throw new ‪NoSuchControllerException('The controller object "' . $objectName . '" does not exist.', 1220884009);
317  }
318  return trim($objectName, '\\');
319  }
320 
325  public static function ‪resolveControllerAliasFromControllerClassName(string $controllerClassName): string
326  {
327  // This method has been adjusted for TYPO3 10.3 to mitigate the issue that controller aliases
328  // could not longer be calculated from controller classes when calling
329  // \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin().
330  //
331  // The idea for version 11 is to let the user choose a controller alias and to check for its
332  // uniqueness per plugin. That way, the core does no longer rely on the namespace of
333  // controller classes to be in a specific format.
334  //
335  // todo: Change the way plugins are registered and enforce a controller alias to be set by
336  // the user to also free the core from guessing a simple alias by looking at the
337  // class name. This makes it possible to choose controller class names without a
338  // controller suffix.
339 
340  $strLen = strlen('Controller');
341 
342  if (!‪StringUtility::endsWith($controllerClassName, 'Controller')) {
343  return '';
344  }
345 
346  $controllerClassNameWithoutControllerSuffix = substr($controllerClassName, 0, -$strLen);
347 
348  if (strrpos($controllerClassNameWithoutControllerSuffix, 'Controller\\') === false) {
349  $positionOfLastSlash = (int)strrpos($controllerClassNameWithoutControllerSuffix, '\\');
350  $positionOfLastSlash += $positionOfLastSlash === 0 ? 0 : 1;
351 
352  return substr($controllerClassNameWithoutControllerSuffix, $positionOfLastSlash);
353  }
354 
355  $positionOfControllerNamespacePart = (int)strrpos(
356  $controllerClassNameWithoutControllerSuffix,
357  'Controller\\'
358  );
359 
360  return substr(
361  $controllerClassNameWithoutControllerSuffix,
362  $positionOfControllerNamespacePart + $strLen + 1
363  );
364  }
365 
371  public static function ‪resolveVendorFromExtensionAndControllerClassName(string $extensionName, string $controllerClassName): string
372  {
373  if (strpos($controllerClassName, '\\') === false) {
374  // Does not work with non namespaced classes
375  return '';
376  }
377 
378  if (false === $extensionNamePosition = strpos($controllerClassName, $extensionName)) {
379  // Does not work for classes that do not include the extension name as namespace part
380  return '';
381  }
382 
383  if (--$extensionNamePosition < 0) {
384  return '';
385  }
386 
387  return substr(
388  $controllerClassName,
389  0,
390  $extensionNamePosition
391  );
392  }
393 
399  public static function ‪registerTypeConverter($typeConverterClassName)
400  {
401  if (!isset(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters']) ||
402  !is_array(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'])
403  ) {
404  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'] = [];
405  }
406  if (!in_array($typeConverterClassName, ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'])) {
407  ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'][] = $typeConverterClassName;
408  }
409  }
410 
418  protected static function ‪checkVendorNameFormat($vendorName, $extensionName)
419  {
420  if (preg_match('/^[A-Z]/', $vendorName) !== 1) {
421  trigger_error('The vendor name from tx_' . $extensionName . ' must begin with a capital letter.', E_USER_DEPRECATED);
422  }
423  }
424 
431  protected static function ‪checkExtensionNameFormat($extensionName)
432  {
433  if (empty($extensionName)) {
434  throw new \InvalidArgumentException('The extension name must not be empty', 1239891990);
435  }
436  }
437 
444  protected static function ‪checkPluginNameFormat($pluginName)
445  {
446  if (empty($pluginName)) {
447  throw new \InvalidArgumentException('The plugin name must not be empty', 1239891988);
448  }
449  }
450 }
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addModule
‪static addModule($main, $sub='', $position='', $path=null, $moduleConfiguration=[])
Definition: ExtensionManagementUtility.php:820
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\resolveVendorFromExtensionAndControllerClassName
‪static string resolveVendorFromExtensionAndControllerClassName(string $extensionName, string $controllerClassName)
Definition: ExtensionUtility.php:371
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\registerPlugin
‪static registerPlugin($extensionName, $pluginName, $pluginTitle, $pluginIcon=null, $group='default')
Definition: ExtensionUtility.php:161
‪TYPO3\CMS\Core\Utility\StringUtility\endsWith
‪static bool endsWith($haystack, $needle)
Definition: StringUtility.php:61
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\resolveControllerAliasFromControllerClassName
‪static string resolveControllerAliasFromControllerClassName(string $controllerClassName)
Definition: ExtensionUtility.php:325
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility
Definition: ExtensionUtility.php:30
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\checkVendorNameFormat
‪static checkVendorNameFormat($vendorName, $extensionName)
Definition: ExtensionUtility.php:418
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\PLUGIN_TYPE_CONTENT_ELEMENT
‪const PLUGIN_TYPE_CONTENT_ELEMENT
Definition: ExtensionUtility.php:32
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\registerModule
‪static registerModule($extensionName, $mainModuleName='', $subModuleName='', $position='', array $controllerActions=[], array $moduleConfiguration=[])
Definition: ExtensionUtility.php:208
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addPlugin
‪static addPlugin($itemArray, $type='list_type', $extensionKey=null)
Definition: ExtensionManagementUtility.php:1244
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\registerTypeConverter
‪static registerTypeConverter($typeConverterClassName)
Definition: ExtensionUtility.php:399
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\PLUGIN_TYPE_PLUGIN
‪const PLUGIN_TYPE_PLUGIN
Definition: ExtensionUtility.php:31
‪TYPO3\CMS\Core\Utility\GeneralUtility\camelCaseToLowerCaseUnderscored
‪static string camelCaseToLowerCaseUnderscored($string)
Definition: GeneralUtility.php:914
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\configurePlugin
‪static configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions=[], $pluginType=self::PLUGIN_TYPE_PLUGIN)
Definition: ExtensionUtility.php:51
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\checkPluginNameFormat
‪static checkPluginNameFormat($pluginName)
Definition: ExtensionUtility.php:444
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\getControllerClassName
‪static string getControllerClassName(string $vendor, string $extensionKey, string $subPackageKey, string $controllerAlias)
Definition: ExtensionUtility.php:291
‪TYPO3\CMS\Extbase\Mvc\Exception\NoSuchControllerException
Definition: NoSuchControllerException.php:26
‪TYPO3\CMS\Extbase\Utility\ExtensionUtility\checkExtensionNameFormat
‪static checkExtensionNameFormat($extensionName)
Definition: ExtensionUtility.php:431
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addTypoScript
‪static addTypoScript(string $key, string $type, string $content, $afterStaticUid=0)
Definition: ExtensionManagementUtility.php:1470
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Extbase\Core\Bootstrap
Definition: Bootstrap.php:43
‪TYPO3\CMS\Extbase\Utility
Definition: DebuggerUtility.php:18
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Core\Utility\GeneralUtility\underscoredToUpperCamelCase
‪static string underscoredToUpperCamelCase($string)
Definition: GeneralUtility.php:890