‪TYPO3CMS  11.5
ModuleLoader.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 
22 
34 {
43  public $modules = [];
44 
50  public $modListGroup = [];
51 
57  public $modListUser = [];
58 
64  public $BE_USER;
65 
71  public $observeWorkspaces = false;
72 
78  protected $navigationComponents = [];
79 
84  protected $moduleLabels = [];
85 
89  public function getModules(): array
90  {
91  return $this->modules;
92  }
93 
102  public function load($modulesArray, ‪BackendUserAuthentication $beUser = null)
103  {
104  // Setting the backend user for use internally
105  $this->‪BE_USER = $beUser ?: ‪$GLOBALS['BE_USER'];
106 
107  // Unset the array for calling backend modules based on external backend module dispatchers in typo3/index.php
108  unset($modulesArray['_configuration']);
109  $this->‪navigationComponents = $modulesArray['_navigationComponents'];
110  unset($modulesArray['_navigationComponents']);
111  ‪$mainModules = $this->parseModulesArray($modulesArray);
112 
113  // Traverses the module setup and creates the internal array $this->modules
114  foreach (‪$mainModules as $mainModuleName => $subModules) {
115  $mainModuleConfiguration = $this->‪checkMod($mainModuleName);
116  // If $mainModuleConfiguration is not set (FALSE) there is no access to the module !(?)
117  if (is_array($mainModuleConfiguration)) {
118  $this->modules[$mainModuleName] = $mainModuleConfiguration;
119  // Load the submodules
120  if (is_array($subModules)) {
121  foreach ($subModules as $subModuleName) {
122  $subModuleConfiguration = $this->‪checkMod($mainModuleName . '_' . $subModuleName);
123  if (is_array($subModuleConfiguration)) {
124  $this->modules[$mainModuleName]['sub'][$subModuleName] = $subModuleConfiguration;
125  }
126  }
127  }
128  } elseif ($mainModuleConfiguration !== false) {
129  // Although the configuration was not found, still check if there are submodules
130  // This must be done in order to fill out the select-lists for modules correctly!!
131  if (is_array($subModules)) {
132  foreach ($subModules as $subModuleName) {
133  $this->‪checkMod($mainModuleName . '_' . $subModuleName);
134  }
135  }
136  }
137  }
138  }
139 
151  public function ‪checkMod($name)
152  {
153  // merge configuration and labels into one array
154  $setupInformation = $this->‪getModuleSetupInformation($name);
155 
156  // clean up the configuration part
157  if (empty($setupInformation['configuration'])) {
158  return 'notFound';
159  }
160  $finalModuleConfiguration = $setupInformation['configuration'];
161  if (!empty($finalModuleConfiguration['shy'])
162  || !$this->‪checkModAccess($name, $setupInformation['configuration'])
163  || !$this->‪checkModWorkspace($name, $setupInformation['configuration'])
164  ) {
165  return false;
166  }
167  $finalModuleConfiguration['name'] = $name;
168  // Language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
169  $this->‪addLabelsForModule($name, $finalModuleConfiguration['labels'] ?? $setupInformation['labels']);
170  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
171  if (isset($setupInformation['configuration']['routeTarget'])) {
172  $finalModuleConfiguration['script'] = (string)$uriBuilder->buildUriFromRoute($name);
173  } else {
174  $finalModuleConfiguration['script'] = (string)$uriBuilder->buildUriFromRoute('dummy');
175  }
176 
177  if (isset($setupInformation['configuration']['component'])) {
178  $finalModuleConfiguration['component'] = $setupInformation['configuration']['component'];
179  } else {
180  $finalModuleConfiguration['component'] = 'TYPO3/CMS/Backend/Module/Iframe';
181  }
182 
183  // @deprecated since TYPO3 v11, will be removed in TYPO3 v12.0
184  if (!empty($setupInformation['configuration']['navigationFrameModule'])) {
185  $finalModuleConfiguration['navFrameScript'] = (string)$uriBuilder->buildUriFromRoute(
186  $setupInformation['configuration']['navigationFrameModule'],
187  !empty($setupInformation['configuration']['navigationFrameModuleParameters'])
188  ? $setupInformation['configuration']['navigationFrameModuleParameters']
189  : []
190  );
191  }
192 
193  // Check if this is a submodule
194  $mainModule = '';
195  if (str_contains($name, '_')) {
196  [$mainModule] = explode('_', $name, 2);
197  }
198 
199  // check if there is a navigation component (like the pagetree)
200  if (is_array($this->‪navigationComponents[$name] ?? false)) {
201  $finalModuleConfiguration['navigationComponentId'] = $this->‪navigationComponents[$name]['componentId'];
202  } elseif ($mainModule
203  && is_array($this->‪navigationComponents[$mainModule] ?? false)
204  && ($setupInformation['configuration']['inheritNavigationComponentFromMainModule'] ?? null) !== false) {
205  // navigation component can be overridden by the main module component
206  $finalModuleConfiguration['navigationComponentId'] = $this->‪navigationComponents[$mainModule]['componentId'];
207  }
208  return $finalModuleConfiguration;
209  }
210 
218  protected function ‪getModuleSetupInformation($moduleName)
219  {
220  $moduleSetupInformation = [
221  'configuration' => [],
222  'labels' => [],
223  ];
224 
225  $moduleConfiguration = !empty(‪$GLOBALS['TBE_MODULES']['_configuration'][$moduleName])
226  ? ‪$GLOBALS['TBE_MODULES']['_configuration'][$moduleName]
227  : null;
228  if ($moduleConfiguration !== null) {
229  // Overlay setup with additional labels
230  if (!empty($moduleConfiguration['labels']) && is_array($moduleConfiguration['labels'])) {
231  if (empty($moduleSetupInformation['labels']['default']) || !is_array($moduleSetupInformation['labels']['default'])) {
232  $moduleSetupInformation['labels']['default'] = $moduleConfiguration['labels'];
233  } else {
234  $moduleSetupInformation['labels']['default'] = array_replace_recursive($moduleSetupInformation['labels']['default'], $moduleConfiguration['labels']);
235  }
236  unset($moduleConfiguration['labels']);
237  }
238  // Overlay setup with additional configuration
239  if (is_array($moduleConfiguration)) {
240  $moduleSetupInformation['configuration'] = array_replace_recursive($moduleSetupInformation['configuration'], $moduleConfiguration);
241  }
242  }
243 
244  // Add some default configuration
245  if ($moduleSetupInformation['configuration'] !== [] && !isset($moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'])) {
246  $moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'] = true;
247  }
248 
249  return $moduleSetupInformation;
250  }
251 
259  public function ‪checkModAccess($name, $MCONF)
260  {
261  if (empty($MCONF['access'])) {
262  return true;
263  }
264  $access = strtolower($MCONF['access']);
265  // Check if this module is only allowed by system maintainers (= admins who are in the list of system maintainers)
266  if (str_contains($MCONF['access'], ‪BackendUserAuthentication::ROLE_SYSTEMMAINTAINER)) {
267  return $this->‪BE_USER->isSystemMaintainer();
268  }
269  // Checking if admin-access is required
270  // If admin-permissions is required then return TRUE if user is admin
271  if (str_contains($access, 'admin') && $this->‪BE_USER->isAdmin()) {
272  return true;
273  }
274  // This will add modules to the select-lists of user and groups
275  if (str_contains($access, 'user')) {
276  $this->modListUser[] = $name;
277  }
278  if (str_contains($access, 'group')) {
279  $this->modListGroup[] = $name;
280  }
281  // This checks if a user is permitted to access the module
282  if ($this->‪BE_USER->isAdmin() || $this->BE_USER->check('modules', $name)) {
283  return true;
284  }
285  return false;
286  }
287 
296  public function ‪checkModWorkspace($name, $MCONF)
297  {
298  if (!$this->observeWorkspaces) {
299  return true;
300  }
301  $status = true;
302  if (!empty($MCONF['workspaces'])) {
303  $status = ($this->‪BE_USER->workspace === 0 && GeneralUtility::inList($MCONF['workspaces'], 'online'))
304  || ($this->‪BE_USER->workspace > 0 && GeneralUtility::inList($MCONF['workspaces'], 'custom'));
305  } elseif ($this->‪BE_USER->workspace === -99) {
306  $status = false;
307  }
308  return $status;
309  }
310 
318  public function parseModulesArray($arr)
319  {
320  ‪$theMods = [];
321  if (is_array($arr)) {
322  foreach ($arr as $mod => $subs) {
323  // Clean module name to alphanum
324  $mod = $this->‪cleanName($mod);
325  if ($mod) {
326  if ($subs) {
327  $subsArr = ‪GeneralUtility::trimExplode(',', $subs);
328  foreach ($subsArr as $subMod) {
329  $subMod = $this->‪cleanName($subMod);
330  if ($subMod) {
331  ‪$theMods[$mod][] = $subMod;
332  }
333  }
334  } else {
335  ‪$theMods[$mod] = 1;
336  }
337  }
338  }
339  }
340  return ‪$theMods;
341  }
342 
350  public function ‪cleanName($str)
351  {
352  return preg_replace('/[^a-z0-9]/i', '', $str);
353  }
354 
368  public function ‪addLabelsForModule($moduleName, $labels)
369  {
370  // If LOCAL_LANG references are used for labels of the module:
371  if (is_string($labels)) {
372  // Extbase-based modules
373  $this->moduleLabels[$moduleName] = [
374  'shortdescription' => $labels . ':mlang_labels_tablabel',
375  'description' => $labels . ':mlang_labels_tabdescr',
376  'title' => $labels . ':mlang_tabs_tab',
377  ];
378  } elseif (isset($labels['title'])) {
379  // New way, where all labels can be LLL references
380  $this->moduleLabels[$moduleName] = $labels;
381  } elseif (isset($labels['ll_ref'])) {
382  // Classic, non-extbase module labels
383  $this->‪addLabelsForModule($moduleName, $labels['ll_ref']);
384  } else {
385  // Very old obsolete approach, don't use anymore, use one of the ways above.
386  if (is_object($this->‪getLanguageService())) {
387  $language = $this->‪getLanguageService()->lang;
388  } else {
389  $language = 'default';
390  }
391 
392  if (isset($labels[$language]['ll_ref'])) {
393  $this->‪addLabelsForModule($moduleName, $labels[$language]['ll_ref']);
394  } elseif (isset($labels['default']['ll_ref'])) {
395  $this->‪addLabelsForModule($moduleName, $labels['default']['ll_ref']);
396  } else {
397  $this->moduleLabels[$moduleName] = [
398  'shortdescription' => $labels[$language]['labels']['tablabel'] ?? $labels['default']['labels']['tablabel'] ?? '',
399  'description' => $labels[$language]['labels']['tabdescr'] ?? $labels['default']['labels']['tabdescr'] ?? '',
400  'title' => $labels[$language]['tabs']['tab'] ?? $labels['default']['tabs']['tab'] ?? '',
401  ];
402  }
403  }
404  }
405 
412  public function ‪getLabelsForModule($moduleName)
413  {
414  return $this->moduleLabels[$moduleName] ?? [];
415  }
416 
420  protected function ‪getLanguageService()
421  {
422  return ‪$GLOBALS['LANG'];
423  }
424 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Backend\Module\ModuleLoader\checkMod
‪foreach($mainModules as $mainModuleName=> $subModules) string bool array checkMod($name)
Definition: ModuleLoader.php:144
‪TYPO3\CMS\Backend\Module\ModuleLoader\checkModWorkspace
‪bool checkModWorkspace($name, $MCONF)
Definition: ModuleLoader.php:289
‪TYPO3\CMS\Backend\Module\ModuleLoader\cleanName
‪array< string, parseModulesArray( $arr) { $theMods=[];if(is_array( $arr)) { foreach( $arr as $mod=> $subs) { $mod=$this-> cleanName($mod)
‪TYPO3\CMS\Backend\Module\ModuleLoader\navigationComponents
‪$this navigationComponents
Definition: ModuleLoader.php:102
‪TYPO3\CMS\Backend\Module\ModuleLoader\cleanName
‪string cleanName($str)
Definition: ModuleLoader.php:343
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\ROLE_SYSTEMMAINTAINER
‪const ROLE_SYSTEMMAINTAINER
Definition: BackendUserAuthentication.php:63
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Backend\Module\ModuleLoader
Definition: ModuleLoader.php:34
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Module\ModuleLoader\getModuleSetupInformation
‪array getModuleSetupInformation($moduleName)
Definition: ModuleLoader.php:211
‪TYPO3\CMS\Backend\Module\ModuleLoader\BE_USER
‪array< string, $modules=array();public array $modListGroup=array();public array $modListUser=array();public \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $BE_USER;public bool $observeWorkspaces=false;protected array $navigationComponents=array();protected array $moduleLabels=array();public array< string, function getModules():array { return $this->modules;} public function load( $modulesArray, BackendUserAuthentication $beUser=null) { $this-> BE_USER
Definition: ModuleLoader.php:98
‪TYPO3\CMS\Backend\Module\ModuleLoader\getLanguageService
‪LanguageService getLanguageService()
Definition: ModuleLoader.php:413
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Module\ModuleLoader\$mainModules
‪$mainModules
Definition: ModuleLoader.php:104
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Backend\Module\ModuleLoader\addLabelsForModule
‪addLabelsForModule($moduleName, $labels)
Definition: ModuleLoader.php:361
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Module\ModuleLoader\checkModAccess
‪bool checkModAccess($name, $MCONF)
Definition: ModuleLoader.php:252
‪TYPO3\CMS\Backend\Module\ModuleLoader\$theMods
‪if($mod) return $theMods
Definition: ModuleLoader.php:318
‪TYPO3\CMS\Backend\Module
Definition: ModuleLoader.php:16
‪TYPO3\CMS\Backend\Module\ModuleLoader\getLabelsForModule
‪array getLabelsForModule($moduleName)
Definition: ModuleLoader.php:405