[FEATURE] Allow flexible configuration for BE submodules 50/21850/4
authorBenjamin Mack <benni@typo3.org>
Wed, 3 Jul 2013 14:42:54 +0000 (16:42 +0200)
committerFelix Kopp <felix-source@phorax.com>
Thu, 4 Jul 2013 13:41:23 +0000 (15:41 +0200)
Previously Backend modules could be configured
via a conf.php file that had $MCONF and $MLANG
variables. Additionally, a Extbase extension could
add more configuration via another API method.
However, the building of the module list
(ModuleLoader) and the internal rendering for
ExtJS (ModuleMenuView) is quite tricky and hard
to override.

The public API call
ExtensionManagementUtility::addModule() has another
parameter now to ship additional configuration that will
override $MCONF from conf.php, or even replace
that information completely, so conf.php will be obsolete.

This is a prerequisite for overriding the configuration
"navigationComponentId" to allow the page tree in other areas
than the web module. Additionally, if the new option
"inheritNavigationComponentFromMainModule" is set to
FALSE (TRUE if not set), then e.g. a web_* module can have
the page tree disabled.

Resolves: #49643
Releases: 6.2
Change-Id: I9790e5e40cbc350925d817846d75ab27ec065255
Reviewed-on: https://review.typo3.org/21850
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
Reviewed-by: Felix Kopp
Tested-by: Felix Kopp
typo3/sysext/backend/Classes/Module/ModuleLoader.php
typo3/sysext/backend/Classes/View/ModuleMenuView.php
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php

index d33829a..12fa156 100644 (file)
@@ -250,93 +250,154 @@ class ModuleLoader {
                if (strpos($name, '_') !== FALSE) {
                        list($mainModule, ) = explode('_', $name, 2);
                }
-               $modconf = array();
+
+               $finalModuleConfiguration = array();
+
+               // merges $MCONF and $MLANG from conf.php and the additional configuration of the module
+               $setupInformation = $this->getModuleSetupInformation($name, $fullpath);
+
                // Because 'path/../path' does not work
-               $path = preg_replace('/\\/[^\\/.]+\\/\\.\\.\\//', '/', $fullpath);
-               if (@is_dir($path) && file_exists($path . '/conf.php')) {
-                       $MCONF = array();
-                       $MLANG = array();
-                       // The conf-file is included. This must be valid PHP.
-                       include $path . '/conf.php';
-                       if (!$MCONF['shy'] && $this->checkModAccess($name, $MCONF) && $this->checkModWorkspace($name, $MCONF)) {
-                               $modconf['name'] = $name;
+               // clean up the configuration part
+               if (count($setupInformation['configuration']) > 0) {
+                       if (!$setupInformation['configuration']['shy'] && $this->checkModAccess($name, $setupInformation['configuration']) && $this->checkModWorkspace($name, $setupInformation['configuration'])) {
+                               $finalModuleConfiguration = $setupInformation['configuration'];
+                               $finalModuleConfiguration['name'] = $name;
                                // Language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
                                if (is_object($GLOBALS['LANG'])) {
-                                       // $MLANG['default']['tabs_images']['tab'] is for modules the reference to the module icon.
+                                       // $setupInformation['labels']['default']['tabs_images']['tab'] is for modules the reference
+                                       // to the module icon.
+                                       $defaultLabels = $setupInformation['labels']['default'];
                                        // Here the path is transformed to an absolute reference.
-                                       if ($MLANG['default']['tabs_images']['tab']) {
+                                       if ($defaultLabels['tabs_images']['tab']) {
                                                // Initializing search for alternative icon:
                                                // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
-                                               $altIconKey = 'MOD:' . $name . '/' . $MLANG['default']['tabs_images']['tab'];
+                                               $altIconKey = 'MOD:' . $name . '/' . $defaultLabels['tabs_images']['tab'];
                                                $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? GeneralUtility::resolveBackPath(PATH_typo3 . $GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
                                                // Setting icon, either default or alternative:
                                                if ($altIconAbsPath && @is_file($altIconAbsPath)) {
-                                                       $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $altIconAbsPath);
+                                                       $defaultLabels['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $altIconAbsPath);
                                                } else {
                                                        // Setting default icon:
-                                                       $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MLANG['default']['tabs_images']['tab']);
+                                                       $defaultLabels['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $defaultLabels['tabs_images']['tab']);
                                                }
+
                                                // Finally, setting the icon with correct path:
-                                               if (substr($MLANG['default']['tabs_images']['tab'], 0, 3) == '../') {
-                                                       $MLANG['default']['tabs_images']['tab'] = PATH_site . substr($MLANG['default']['tabs_images']['tab'], 3);
+                                               if (substr($defaultLabels['tabs_images']['tab'], 0, 3) == '../') {
+                                                       $defaultLabels['tabs_images']['tab'] = PATH_site . substr($defaultLabels['tabs_images']['tab'], 3);
                                                } else {
-                                                       $MLANG['default']['tabs_images']['tab'] = PATH_typo3 . $MLANG['default']['tabs_images']['tab'];
+                                                       $defaultLabels['tabs_images']['tab'] = PATH_typo3 . $defaultLabels['tabs_images']['tab'];
                                                }
                                        }
+
                                        // If LOCAL_LANG references are used for labels of the module:
-                                       if ($MLANG['default']['ll_ref']) {
+                                       if ($defaultLabels['ll_ref']) {
                                                // Now the 'default' key is loaded with the CURRENT language - not the english translation...
-                                               $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tablabel');
-                                               $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tabdescr');
-                                               $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_tabs_tab');
-                                               $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
+                                               $defaultLabels['labels']['tablabel'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_labels_tablabel');
+                                               $defaultLabels['labels']['tabdescr'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_labels_tabdescr');
+                                               $defaultLabels['tabs']['tab'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_tabs_tab');
+                                               $GLOBALS['LANG']->addModuleLabels($defaultLabels, $name . '_');
                                        } else {
                                                // ... otherwise use the old way:
-                                               $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
-                                               $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang], $name . '_');
+                                               $GLOBALS['LANG']->addModuleLabels($defaultLabels, $name . '_');
+                                               $GLOBALS['LANG']->addModuleLabels($setupInformation['labels'][$GLOBALS['LANG']->lang], $name . '_');
                                        }
                                }
+
                                // Default script setup
-                               if ($MCONF['script'] === '_DISPATCH') {
-                                       if ($MCONF['extbase']) {
-                                               $modconf['script'] = 'mod.php?M=Tx_' . rawurlencode($name);
+                               if ($setupInformation['configuration']['script'] === '_DISPATCH') {
+                                       if ($setupInformation['configuration']['extbase']) {
+                                               $finalModuleConfiguration['script'] = 'mod.php?M=Tx_' . rawurlencode($name);
                                        } else {
-                                               $modconf['script'] = 'mod.php?M=' . rawurlencode($name);
+                                               $finalModuleConfiguration['script'] = 'mod.php?M=' . rawurlencode($name);
                                        }
-                               } elseif ($MCONF['script'] && file_exists($path . '/' . $MCONF['script'])) {
-                                       $modconf['script'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['script']);
+                               } elseif ($setupInformation['configuration']['script'] && file_exists($setupInformation['path'] . '/' . $setupInformation['configuration']['script'])) {
+                                       $finalModuleConfiguration['script'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $setupInformation['configuration']['script']);
                                } else {
-                                       $modconf['script'] = 'dummy.php';
+                                       $finalModuleConfiguration['script'] = 'dummy.php';
                                }
+
                                // Default tab setting
-                               if ($MCONF['defaultMod']) {
-                                       $modconf['defaultMod'] = $MCONF['defaultMod'];
+                               if ($setupInformation['configuration']['defaultMod']) {
+                                       $finalModuleConfiguration['defaultMod'] = $setupInformation['configuration']['defaultMod'];
                                }
+
                                // Navigation Frame Script (GET params could be added)
-                               if ($MCONF['navFrameScript']) {
-                                       $navFrameScript = explode('?', $MCONF['navFrameScript']);
+                               if ($setupInformation['configuration']['navFrameScript']) {
+                                       $navFrameScript = explode('?', $setupInformation['configuration']['navFrameScript']);
                                        $navFrameScript = $navFrameScript[0];
-                                       if (file_exists($path . '/' . $navFrameScript)) {
-                                               $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['navFrameScript']);
+                                       if (file_exists($setupInformation['path'] . '/' . $navFrameScript)) {
+                                               $finalModuleConfiguration['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $setupInformation['configuration']['navFrameScript']);
                                        }
                                }
+
                                // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
-                               if ($MCONF['navFrameScriptParam']) {
-                                       $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
+                               if ($setupInformation['configuration']['navFrameScriptParam']) {
+                                       $finalModuleConfiguration['navFrameScriptParam'] = $setupInformation['configuration']['navFrameScriptParam'];
                                }
+
                                // check if there is a navigation component (like the pagetree)
                                if (is_array($this->navigationComponents[$name])) {
-                                       $modconf['navigationComponentId'] = $this->navigationComponents[$name]['componentId'];
-                               } elseif ($mainModule && is_array($this->navigationComponents[$mainModule])) {
-                                       $modconf['navigationComponentId'] = $this->navigationComponents[$mainModule]['componentId'];
+                                       $finalModuleConfiguration['navigationComponentId'] = $this->navigationComponents[$name]['componentId'];
+                               // navigation component can be overriden by the main module component
+                               } elseif ($mainModule && is_array($this->navigationComponents[$mainModule]) && $setupInformation['configuration']['inheritNavigationComponentFromMainModule'] !== FALSE) {
+                                       $finalModuleConfiguration['navigationComponentId'] = $this->navigationComponents[$mainModule]['componentId'];
                                }
                        } else {
                                return FALSE;
                        }
                } else {
-                       $modconf = 'notFound';
+                       $finalModuleConfiguration = 'notFound';
+               }
+
+               return $finalModuleConfiguration;
+       }
+
+       /**
+        * fetches the conf.php file of a certain module, and also merges that with
+        * some additional configuration
+        *
+        * @param \string $moduleName the combined name of the module, can be "web", "web_info", or "tools_log"
+        * @param \string $pathToModuleDirectory the path where the module data is put, used for the conf.php or the modScript
+        * @return array an array with subarrays, named "configuration" (aka $MCONF), "labels" (previously known as $MLANG) and the stripped path
+        */
+       protected function getModuleSetupInformation($moduleName, $pathToModuleDirectory) {
+
+               // Because 'path/../path' does not work
+               $path = preg_replace('/\\/[^\\/.]+\\/\\.\\.\\//', '/', $pathToModuleDirectory);
+
+               $moduleSetupInformation = array(
+                       'configuration' => array(),
+                       'labels' => array(),
+                       'path' => $path
+               );
+
+               if (@is_dir($path) && file_exists($path . '/conf.php')) {
+                       $MCONF = array();
+                       $MLANG = array();
+
+                       // The conf-file is included. This must be valid PHP.
+                       include $path . '/conf.php';
+
+                       // move the global variables defined in conf.php into the local method
+                       if (is_array($MCONF)) {
+                               $moduleSetupInformation['configuration'] = $MCONF;
+                       } else {
+                               $moduleSetupInformation['configuration'] = array();
+                       }
+                       $moduleSetupInformation['labels'] = $MLANG;
                }
-               return $modconf;
+
+               // overlay them with additional setup information and configuration
+               if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$moduleName])) {
+                       $moduleSetupInformation['configuration'] = array_merge_recursive($moduleSetupInformation['configuration'], $GLOBALS['TBE_MODULES']['_configuration'][$moduleName]);
+               }
+
+               // add some default configuration
+               if (!isset($moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'])) {
+                       $moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'] = TRUE;
+               }
+
+               return $moduleSetupInformation;
        }
 
        /**
index 4038fa3..94e6149 100644 (file)
@@ -225,7 +225,9 @@ class ModuleMenuView {
                                                'navigationFrameScriptParam' => $submoduleData['navFrameScriptParam'],
                                                'navigationComponentId' => $submoduleData['navigationComponentId']
                                        );
-                                       if ($moduleData['navFrameScript']) {
+                                       // if the main module has a navframe script, inherit to the submodule,
+                                       // but only if it is not disabled explicitly (option is set to FALSE)
+                                       if ($moduleData['navFrameScript'] && $submoduleData['inheritNavigationComponentFromMainModule'] !== FALSE) {
                                                $modules[$moduleKey]['subitems'][$submoduleKey]['parentNavigationFrameScript'] = $moduleData['navFrameScript'];
                                        }
                                }
index e5eb01d..e7828c7 100644 (file)
@@ -796,9 +796,10 @@ class ExtensionManagementUtility {
         * @param string $sub The submodule key. If $sub is not set a blank $main module is created.
         * @param string $position 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.
         * @param string $path The absolute path to the module. If this value is defined the path is added as an entry in $TBE_MODULES['_PATHS'][  main_sub  ] = $path; and thereby tells the backend where the newly added modules is found in the system.
+        * @param array $moduleConfiguration additional configuration, previously put in "conf.php" of the module directory
         * @return void
         */
-       static public function addModule($main, $sub = '', $position = '', $path = '') {
+       static public function addModule($main, $sub = '', $position = '', $path = '', $moduleConfiguration = array()) {
                if (isset($GLOBALS['TBE_MODULES'][$main]) && $sub) {
                        // If there is already a main module by this name:
                        // Adding the submodule to the correct position:
@@ -839,9 +840,15 @@ class ExtensionManagementUtility {
                        // Create new main modules with only one submodule, $sub (or none if $sub is blank)
                        $GLOBALS['TBE_MODULES'][$main] = $sub;
                }
+               $fullModuleSignature = $main . ($sub ? '_' . $sub : '');
                // Adding path:
                if ($path) {
-                       $GLOBALS['TBE_MODULES']['_PATHS'][$main . ($sub ? '_' . $sub : '')] = $path;
+                       $GLOBALS['TBE_MODULES']['_PATHS'][$fullModuleSignature] = $path;
+               }
+
+               // add additional configuration
+               if (is_array($moduleConfiguration) && count($moduleConfiguration) > 0) {
+                       $GLOBALS['TBE_MODULES']['_configuration'][$fullModuleSignature] = $moduleConfiguration;
                }
        }