diff --git a/application/menunode.class.inc.php b/application/menunode.class.inc.php index b4db18ae0..0369c4135 100644 --- a/application/menunode.class.inc.php +++ b/application/menunode.class.inc.php @@ -103,7 +103,7 @@ class ApplicationMenu { self::$sFavoriteSiloQuery = $sOQL; } - + /** * Get the query used to limit the list of displayed organizations in the drop-down menu * @return string The OQL query returning a list of Organization objects @@ -273,12 +273,23 @@ class ApplicationMenu continue; } + $aSubMenuNodes = static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams); + if (! MFCompiler::$bUseLegacyMenuCompilation && !($oMenuNode instanceof ShortcutMenuNode)){ + if (is_array($aSubMenuNodes) && 0 === sizeof($aSubMenuNodes)){ + IssueLog::Error('Empty menu node not displayed', LogChannels::CONSOLE, [ + 'menu_node_class' => get_class($oMenuNode), + 'menu_node_label' => $oMenuNode->GetLabel(), + ]); + continue; + } + } + $aMenuGroups[] = [ 'sId' => $oMenuNode->GetMenuID(), 'sIconCssClasses' => $oMenuNode->GetDecorationClasses(), 'sInitials' => $oMenuNode->GetInitials(), 'sTitle' => $oMenuNode->GetTitle(), - 'aSubMenuNodes' => static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams), + 'aSubMenuNodes' => $aSubMenuNodes, ]; } @@ -525,7 +536,7 @@ EOF return -1; } - + /** * Retrieves the currently active menu (if any, otherwise the first menu is the default) * @return string The Id of the currently active menu @@ -533,7 +544,7 @@ EOF public static function GetActiveNodeId() { $oAppContext = new ApplicationContext(); - $sMenuId = $oAppContext->GetCurrentValue('menu', null); + $sMenuId = $oAppContext->GetCurrentValue('menu', null); if ($sMenuId === null) { $sMenuId = self::GetDefaultMenuId(); @@ -643,7 +654,7 @@ abstract class MenuNode /** * Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu - */ + */ protected $m_aEnableStimuli; /** @@ -804,7 +815,7 @@ abstract class MenuNode { return false; } - + /** * Add a limiting display condition for the same menu node. The conditions will be combined with a AND * @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction @@ -977,7 +988,7 @@ class TemplateMenuNode extends MenuNode * @var string */ protected $sTemplateFile; - + /** * Create a menu item based on a custom template and inserts it into the application's main menu * @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary) @@ -1048,7 +1059,7 @@ class OQLMenuNode extends MenuNode * @var bool|null */ protected $bSearchFormOpen; - + /** * Extra parameters to be passed to the display block to fine tune its appearence */ @@ -1081,7 +1092,7 @@ class OQLMenuNode extends MenuNode // Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects // of the class specified by the OQL... } - + /** * Set some extra parameters to be passed to the display block to fine tune its appearence * @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters @@ -1109,7 +1120,7 @@ class OQLMenuNode extends MenuNode 'Menu_'.$this->GetMenuId(), $this->bSearch, // Search pane $this->bSearchFormOpen, // Search open - $oPage, + $oPage, array_merge($this->m_aParams, $aExtraParams), true ); @@ -1343,10 +1354,10 @@ class NewObjectMenuNode extends MenuNode { // Enable this menu, only if the current user has enough rights to create such an object, or an object of // any child class - + $aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself $bActionIsAllowed = false; - + foreach($aSubClasses as $sCandidateClass) { if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) @@ -1355,7 +1366,7 @@ class NewObjectMenuNode extends MenuNode break; // Enough for now } } - return $bActionIsAllowed; + return $bActionIsAllowed; } /** @@ -1497,7 +1508,7 @@ class DashboardMenuNode extends MenuNode throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'"); } } - + } /** @@ -1538,7 +1549,7 @@ class ShortcutContainerMenuNode extends MenuNode $sName = $this->GetMenuId().'_'.$oShortcut->GetKey(); new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++); } - + // Complete the tree // parent::PopulateChildMenus(); diff --git a/core/config.class.inc.php b/core/config.class.inc.php index f2f0f655f..6c2c94c0e 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -333,14 +333,6 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'set_menu_compilation_algorithm' => [ - 'type' => 'string', - 'description' => 'setup menu compilation algorithm version (N°4762)', - 'default' => 'v1', - 'value' => 'v1', - 'source_of_value' => '', - 'show_in_conf_sample' => false, - ], 'allow_target_creation' => [ 'type' => 'bool', 'description' => 'Displays the + button on external keys to create target objects', diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index 247ee68a3..2edc2a197 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -24,7 +24,6 @@ use Combodo\iTop\DesignElement; require_once(APPROOT.'setup/setuputils.class.inc.php'); require_once(APPROOT.'setup/modelfactory.class.inc.php'); require_once(APPROOT.'core/moduledesign.class.inc.php'); -require_once(APPROOT.'setup/parentmenunodecompiler.class.inc.php'); class DOMFormatException extends Exception { @@ -91,6 +90,8 @@ class MFCompiler */ const REBUILD_HKEYS_NEVER = APPROOT.'data/.setup-rebuild-hkeys-never'; + public static $bUseLegacyMenuCompilation = false; + /** @var \ModelFactory */ protected $oFactory; @@ -127,6 +128,10 @@ class MFCompiler $this->aClassesCSSRules = []; } + public static function UseLegacyMenuCompilation(){ + self::$bUseLegacyMenuCompilation = true; + } + protected function Log($sText) { $this->aLog[] = $sText; @@ -274,11 +279,7 @@ class MFCompiler try { - if (! is_null($oConfig) && $oConfig->Get('set_menu_compilation_algorithm') === 'v2'){ - $this->DoNewCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks); - } else { - $this->DoCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks); - } + $this->DoCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks); } catch (Exception $e) { @@ -510,7 +511,7 @@ EOF; { throw new Exception("Module '{$oModule->GetId()}' (location : '$sModuleRootDir') contains an unknown menuId : '$sMenuId'"); } - if ($oMenuNode->getAttribute("xsi:type") == 'MenuGroup') + if (self::$bUseLegacyMenuCompilation && $oMenuNode->getAttribute("xsi:type") == 'MenuGroup') { // Note: this algorithm is wrong // 1 - the module may appear empty in the current module, while children are defined in other modules @@ -724,483 +725,6 @@ EOF } // DoCompile() - /** - * @since 3.0.x N°4762 - * Perform the enhanced "Compilation" of all modules - * @param string $sTempTargetDir - * @param string $sFinalTargetDir - * @param Page $oP - * @param bool $bUseSymbolicLinks - * @throws Exception - */ - protected function DoNewCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks = false) - { - $aAllClasses = []; // flat list of classes - $aModulesInfo = []; // Hash array of module_name => array('version' => string, 'root_dir' => string) - - // Determine the target modules for the MENUS - // - $aMenuNodes = []; - $aMenusByModule = []; - foreach ($this->oFactory->GetNodes('menus/menu') as $oMenuNode) - { - $sMenuId = $oMenuNode->getAttribute('id'); - $aMenuNodes[$sMenuId] = $oMenuNode; - - $sModuleMenu = $oMenuNode->getAttribute('_created_in'); - $aMenusByModule[$sModuleMenu][] = $sMenuId; - } - - // Determine the target module (exactly one!) for USER RIGHTS - // This used to be based solely on the module which created the user_rights node first - // Unfortunately, our sample extension was delivered with the xml structure, resulting in the new module to be the recipient of the compilation - // Then model.itop-profiles-itil would not exist... resulting in an error after the compilation (and the actual product of the compiler would never be included - // The bullet proof implementation would be to compile in a separate directory as it has been done with the dictionaries... that's another story - $aModules = $this->oFactory->GetLoadedModules(); - $sUserRightsModule = ''; - foreach ($aModules as $foo => $oModule) { - if ($oModule->GetName() == 'itop-profiles-itil') { - $sUserRightsModule = 'itop-profiles-itil'; - break; - } - } - $oUserRightsNode = $this->oFactory->GetNodes('user_rights')->item(0); - if ($oUserRightsNode && ($sUserRightsModule == '')) { - // Legacy algorithm (itop <= 2.0.3) - $sUserRightsModule = $oUserRightsNode->getAttribute('_created_in'); - } - $this->Log("User Rights module found: '$sUserRightsModule'"); - - // List root classes - // - $this->aRootClasses = []; - foreach ($this->oFactory->ListRootClasses() as $oClass) { - $this->Log("Root class (with child classes): ".$oClass->getAttribute('id')); - $this->aRootClasses[$oClass->getAttribute('id')] = $oClass; - } - - $this->LoadSnippets(); - - // Compile, module by module - // - $aModules = $this->oFactory->GetLoadedModules(); - $aDataModelFiles = []; - $aWebservicesFiles = []; - $iStart = strlen(realpath(APPROOT)); - $sRelFinalTargetDir = substr($sFinalTargetDir, strlen(APPROOT)); - - $this->WriteStaticOnlyHtaccess($sTempTargetDir); - $this->WriteStaticOnlyWebConfig($sTempTargetDir); - - static::SetUseSymbolicLinksFlag($bUseSymbolicLinks); - - $aParentModuleRootDirs = []; - $aParentMenuNodes = []; - foreach ($aModules as $foo => $oModule) { - $sModuleName = $oModule->GetName(); - $sModuleVersion = $oModule->GetVersion(); - - $sModuleRootDir = $oModule->GetRootDir(); - if ($sModuleRootDir != '') { - $sModuleRootDir = realpath($sModuleRootDir); - $sRelativeDir = basename($sModuleRootDir); - if ($bUseSymbolicLinks) { - $sRealRelativeDir = substr($sModuleRootDir, $iStart); - } else { - $sRealRelativeDir = $sRelFinalTargetDir.'/'.$sRelativeDir; - } - - // Push the other module files - SetupUtils::copydir($sModuleRootDir, $sTempTargetDir.'/'.$sRelativeDir, $bUseSymbolicLinks); - } else { - $sRelativeDir = $sModuleName; - $sRealRelativeDir = $sModuleName; - } - $aModulesInfo[$sModuleName] = array('root_dir' => $sRealRelativeDir, 'version' => $sModuleVersion); - - $sCompiledCode = ''; - - $oConstants = $this->oFactory->ListConstants($sModuleName); - if ($oConstants->length > 0) - { - foreach($oConstants as $oConstant) - { - $sCompiledCode .= $this->CompileConstant($oConstant)."\n"; - } - } - - if (array_key_exists($sModuleName, $this->aSnippets)) - { - foreach( $this->aSnippets[$sModuleName]['before'] as $aSnippet) - { - $sCompiledCode .= "\n"; - $sCompiledCode .= "/**\n"; - $sCompiledCode .= " * Snippet: {$aSnippet['snippet_id']}\n"; - $sCompiledCode .= " */\n"; - $sCompiledCode .= $aSnippet['content']."\n"; - } - } - - - $oClasses = $this->oFactory->ListClasses($sModuleName); - $iClassCount = $oClasses->length; - if ($iClassCount == 0) - { - $this->Log("Found module without classes declared: $sModuleName"); - } - else - { - /** @var \MFElement $oClass */ - foreach($oClasses as $oClass) - { - $sClass = $oClass->getAttribute("id"); - $aAllClasses[] = $sClass; - try - { - $sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir); - } - catch (DOMFormatException $e) - { - $sMessage = "Failed to process class '$sClass', "; - if (!empty($sModuleRootDir)) { - $sMessage .= "from '$sModuleRootDir': "; - } - $sMessage .= $e->getMessage(); - throw new Exception($sMessage); - } - } - } - - if (!array_key_exists($sModuleName, $aMenusByModule)) - { - $this->Log("Found module without menus declared: $sModuleName"); - } - else - { - $sMenuCreationClass = 'MenuCreation_'.preg_replace('/[^A-Za-z0-9_]/', '_', $sModuleName); - $sCompiledCode .= - <<GetChildText('parent', null)) - { - $aMenusToLoad[] = $sParent; - if (!array_key_exists($sParent, $aParentModuleRootDirs)){ - $aParentModuleRootDirs[$sParent] = $sModuleRootDir; - } - } - // Note: the order matters: the parents must be defined BEFORE - $aMenusToLoad[] = $sMenuId; - } - $aMenusToLoad = array_unique($aMenusToLoad); - $aMenuLinesForAll = []; - $aMenuLinesForAdmins = []; - $aAdminMenus = []; - foreach($aMenusToLoad as $sMenuId) - { - $oMenuNode = $aMenuNodes[$sMenuId]; - if (is_null($oMenuNode)) - { - throw new Exception("Module '{$oModule->GetId()}' (location : '$sModuleRootDir') contains an unknown menuId : '$sMenuId'"); - } - if ($oMenuNode->getAttribute("xsi:type") == 'MenuGroup' || array_key_exists($sMenuId, $aParentModuleRootDirs)) - { - $aParentMenuNodes[$sMenuId] = $oMenuNode; - $sParent = $oMenuNode->GetChildText('parent', null); - if (($oMenuNode->GetChildText('enable_admin_only') == '1') || isset($aAdminMenus[$sParent])) - { - $aAdminMenus[$sMenuId] = true; - } - continue; - - // Note: this algorithm is wrong - // 1 - the module may appear empty in the current module, while children are defined in other modules - // 2 - check recursively that child nodes are not empty themselves - // Future algorithm: - // a- browse the modules and build the menu tree - // b- browse the tree and blacklist empty menus - // c- before compiling, discard if blacklisted - } - try - { - $aMenuLines = $this->CompileMenu($oMenuNode, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); - } - catch (DOMFormatException $e) - { - throw new Exception("Failed to process menu '$sMenuId', from '$sModuleRootDir': ".$e->getMessage()); - } - $sParent = $oMenuNode->GetChildText('parent', null); - if (($oMenuNode->GetChildText('enable_admin_only') == '1') || isset($aAdminMenus[$sParent])) - { - $aMenuLinesForAdmins = array_merge($aMenuLinesForAdmins, $aMenuLines); - $aAdminMenus[$oMenuNode->getAttribute("id")] = true; - } - else - { - $aMenuLinesForAll = array_merge($aMenuLinesForAll, $aMenuLines); - } - } - $sIndent = "\t\t"; - foreach ($aMenuLinesForAll as $sPHPLine) - { - $sCompiledCode .= $sIndent.$sPHPLine."\n"; - } - if (count($aMenuLinesForAdmins) > 0) - { - $sCompiledCode .= $sIndent."if (UserRights::IsAdministrator())\n"; - $sCompiledCode .= $sIndent."{\n"; - foreach ($aMenuLinesForAdmins as $sPHPLine) - { - $sCompiledCode .= $sIndent."\t".$sPHPLine."\n"; - } - $sCompiledCode .= $sIndent."}\n"; - } - $sCompiledCode .= - <<CompileUserRights($oUserRightsNode); - } - - if (array_key_exists($sModuleName, $this->aSnippets)) - { - foreach( $this->aSnippets[$sModuleName]['after'] as $aSnippet) - { - $sCompiledCode .= "\n"; - $sCompiledCode .= "/**\n"; - $sCompiledCode .= " * Snippet: {$aSnippet['snippet_id']}\n"; - $sCompiledCode .= " */\n"; - $sCompiledCode .= $aSnippet['content']."\n"; - } - } - - // Create (overwrite if existing) the compiled file - // - if (strlen($sCompiledCode) > 0) - { - // We have compiled something: write the code somewhere - // - if (strlen($sModuleRootDir) > 0) - { - // Write the code into the given module as model..php - // - $sResultFile = $sTempTargetDir.'/'.$sRelativeDir.'/model.'.$sModuleName.'.php'; - $this->WritePHPFile($sResultFile, $sModuleName, $sModuleVersion, $sCompiledCode); - } - else - { - // Write the code into core/main.php - // - $this->sMainPHPCode .= - <<sMainPHPCode .= $sCompiledCode; - } - } - else - { - $this->Log("Compilation of module $sModuleName in version $sModuleVersion produced not code at all. No file written."); - } - - // files to include (PHP datamodels) - foreach($oModule->GetFilesToInclude('business') as $sRelFileName) - { - $aDataModelFiles[] = "MetaModel::IncludeModule(MODULESROOT.'/$sRelativeDir/$sRelFileName');"; - } - // files to include (PHP webservices providers) - foreach($oModule->GetFilesToInclude('webservices') as $sRelFileName) - { - $aWebservicesFiles[] = "MetaModel::IncludeModule(MODULESROOT.'/$sRelativeDir/$sRelFileName');"; - } - } // foreach module - - // Compile the dictionaries -out of the modules - // - $sDictDir = $sTempTargetDir.'/dictionaries'; - if (!is_dir($sDictDir)) - { - $this->Log("Creating directory $sDictDir"); - mkdir($sDictDir, 0777, true); - } - - $oDictionaries = $this->oFactory->GetNodes('dictionaries/dictionary'); - $this->CompileDictionaries($oDictionaries, $sTempTargetDir, $sFinalTargetDir); - - // Compile the branding - // - $oBrandingNode = $this->oFactory->GetNodes('branding')->item(0); - $this->CompileBranding($oBrandingNode, $sTempTargetDir, $sFinalTargetDir); - - if (array_key_exists('_core_', $this->aSnippets)) - { - foreach( $this->aSnippets['_core_']['before'] as $aSnippet) - { - $this->sMainPHPCode .= "\n"; - $this->sMainPHPCode .= "/**\n"; - $this->sMainPHPCode .= " * Snippet: {$aSnippet['snippet_id']}\n"; - $this->sMainPHPCode .= " */\n"; - $this->sMainPHPCode .= $aSnippet['content']."\n"; - } - } - - // Compile the portals - $oPortalsNode = $this->oFactory->GetNodes('/itop_design/portals')->item(0); - $this->CompilePortals($oPortalsNode, $sTempTargetDir, $sFinalTargetDir); - - // Create module design XML files - $oModuleDesignsNode = $this->oFactory->GetNodes('/itop_design/module_designs')->item(0); - $this->CompileModuleDesigns($oModuleDesignsNode, $sTempTargetDir, $sFinalTargetDir); - - // Compile the XML parameters - $oParametersNode = $this->oFactory->GetNodes('/itop_design/module_parameters')->item(0); - $this->CompileParameters($oParametersNode, $sTempTargetDir, $sFinalTargetDir); - - if (array_key_exists('_core_', $this->aSnippets)) - { - foreach( $this->aSnippets['_core_']['after'] as $aSnippet) - { - $this->sMainPHPCode .= "\n"; - $this->sMainPHPCode .= "/**\n"; - $this->sMainPHPCode .= " * Snippet: {$aSnippet['snippet_id']}\n"; - $this->sMainPHPCode .= " */\n"; - $this->sMainPHPCode .= $aSnippet['content']."\n"; - } - } - - if (count($this->aRelations) > 0) - { - $this->sMainPHPCode .= "\n"; - $this->sMainPHPCode .= "/**\n"; - $this->sMainPHPCode .= " * Relations\n"; - $this->sMainPHPCode .= " */\n"; - foreach($this->aRelations as $sRelationCode => $aData) - { - $sRelCodeSafe = addslashes($sRelationCode); - $this->sMainPHPCode .= "MetaModel::RegisterRelation('$sRelCodeSafe');\n"; - } - } - - // Write core/main.php - SetupUtils::builddir($sTempTargetDir.'/core'); - $sPHPFile = $sTempTargetDir.'/core/main.php'; - file_put_contents($sPHPFile, $this->sMainPHPCode); - - $this->GenerateMenuNodePhpCode($aParentModuleRootDirs, $aParentMenuNodes, $aAdminMenus, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); - - $sCurrDate = date(DATE_ISO8601); - // Autoload - $sPHPFile = $sTempTargetDir.'/autoload.php'; - $sPHPFileContent = - << $sModuleRootDir) { - $oCompileParentMenuNode->CompileParentMenuNode($sMenuId); - } - - $aMenuLinesForAdmins = $oCompileParentMenuNode->GetMenuLinesForAdmins(); - $aMenuLinesForAll = $oCompileParentMenuNode->GetMenuLinesForAll(); - - $sCurrDate = date(DATE_ISO8601); - $sCompiledCode = - << 0) - { - $sCompiledCode .= $sIndent."if (UserRights::IsAdministrator())\n"; - $sCompiledCode .= $sIndent."{\n"; - foreach ($aMenuLinesForAdmins as $sPHPLine) - { - $sCompiledCode .= $sIndent."\t".$sPHPLine."\n"; - } - $sCompiledCode .= $sIndent."}\n"; - } - - $sCompiledCode .= <<oMFCompiler = $oMFCompiler; - $this->aParentModuleRootDirs = $aParentModuleRootDirs; - $this->aParentMenuNodes = $aParentMenuNodes; - $this->aAdminMenus = $aAdminMenus; - $this->sTempTargetDir = $sTempTargetDir; - $this->sFinalTargetDir = $sFinalTargetDir; - $this->sRelativeDir = $sRelativeDir; - $this->oP = $oP; - } - - public function CompileParentMenuNode(string $sMenuId) : void - { - $sStatus = array_key_exists($sMenuId, $this->aMenuProcessStatus) ? $this->aMenuProcessStatus[$sMenuId] : null; - if ($sStatus === self::COMPILED){ - //node already processed before - return; - } else if ($sStatus === self::COMPILING){ - throw new \Exception("Cyclic dependency between parent menus ($sMenuId)"); - } - - $this->aMenuProcessStatus[$sMenuId] = self::COMPILING; - - try { - if (! array_key_exists($sMenuId, $this->aParentMenuNodes)){ - throw new Exception("Failed to process parent menu '$sMenuId' that is referenced by a child but not defined"); - } - $oMenuNode = $this->aParentMenuNodes[$sMenuId]; - - $sParent = $oMenuNode->GetChildText('parent', null); - if (! empty($sParent)){ - //compile parents before (even parent of parents ... recursively) - $this->CompileParentMenuNode($sParent); - } - - if (! array_key_exists($sMenuId, $this->aParentModuleRootDirs)){ - throw new Exception("Failed to process parent menu '$sMenuId' that is referenced by a child but not defined"); - } - $sModuleRootDir = $this->aParentModuleRootDirs[$sMenuId]; - - $aMenuLines = $this->oMFCompiler->CompileMenu($oMenuNode, $this->sTempTargetDir, $this->sFinalTargetDir, $this->sRelativeDir, $this->oP); - } catch (DOMFormatException $e) { - throw new Exception("Failed to process menu '$sMenuId', from '$sModuleRootDir': ".$e->getMessage()); - } - $sParent = $oMenuNode->GetChildText('parent', null); - if (($oMenuNode->GetChildText('enable_admin_only') == '1') || isset($this->aAdminMenus[$sParent])) { - $this->aMenuLinesForAdmins = array_merge($this->aMenuLinesForAdmins, $aMenuLines); - $this->aAdminMenus[$oMenuNode->getAttribute("id")] = true; - } else { - $this->aMenuLinesForAll = array_merge($this->aMenuLinesForAll, $aMenuLines); - } - - $this->aMenuProcessStatus[$sMenuId] = self::COMPILED; - } - - public function GetMenuLinesForAdmins(): array { - return $this->aMenuLinesForAdmins; - } - - public function GetMenuLinesForAll(): array { - return $this->aMenuLinesForAll; - } - - -} diff --git a/test/setup/MFCompilerMenuTest.php b/test/setup/MFCompilerMenuTest.php index c7803cb6f..6926e159d 100644 --- a/test/setup/MFCompilerMenuTest.php +++ b/test/setup/MFCompilerMenuTest.php @@ -19,11 +19,14 @@ use RunTimeEnvironment; */ class MFCompilerMenuTest extends ItopTestCase { private static $aPreviousEnvMenus; + private static $aPreviousEnvMenuCount; public function setUp(): void { parent::setUp(); require_once(APPROOT.'setup/compiler.class.inc.php'); require_once(APPROOT.'setup/modelfactory.class.inc.php'); + require_once(APPROOT.'application/utils.inc.php'); + } public function tearDown(): void { @@ -32,40 +35,37 @@ class MFCompilerMenuTest extends ItopTestCase { public function CompileMenusProvider(){ return [ - 'production' => ['production'], - 'phpunit' => ['phpunit'], + 'legacy_algo' => [ 'sEnv' => 'legacy_algo', 'bLegacyMenuCompilation' => true ], + 'menu_compilation_fix' => [ 'sEnv' => 'menu_compilation_fix', 'bLegacyMenuCompilation' => false ], ]; } /** * @dataProvider CompileMenusProvider */ - public function testCompileMenus($sEnv){ - if(\utils::GetCurrentEnvironment() != $sEnv) { - $sConfigFilePath = \utils::GetConfigFilePath($sEnv); + public function testCompileMenus($sEnv, $bLegacyMenuCompilation){ + $sConfigFilePath = \utils::GetConfigFilePath($sEnv); - //copy conf from production to phpunit context - $sDirPath = dirname($sConfigFilePath); - if (! is_dir($sDirPath)){ - mkdir($sDirPath); - } - $oConfig = new Config(\utils::GetConfigFilePath()); - $oConfig->WriteToFile($sConfigFilePath); - - $oConfig = new Config($sConfigFilePath); - $oConfig->Set('set_menu_compilation_algorithm', 'v2', 'test', true); - $oConfig->WriteToFile(); - $oRunTimeEnvironment = new RunTimeEnvironment($sEnv); - $oRunTimeEnvironment->CompileFrom(\utils::GetCurrentEnvironment()); - $oConfig->Set('set_menu_compilation_algorithm', 'v1', 'test', true); - $oConfig->WriteToFile(); + //copy conf from production to phpunit context + $sDirPath = dirname($sConfigFilePath); + if (! is_dir($sDirPath)){ + mkdir($sDirPath); } + $oConfig = new Config(\utils::GetConfigFilePath()); + $oConfig->WriteToFile($sConfigFilePath); + + $oConfig = new Config($sConfigFilePath); + if ($bLegacyMenuCompilation){ + MFCompiler::UseLegacyMenuCompilation(); + } + $oConfig->WriteToFile(); + $oRunTimeEnvironment = new RunTimeEnvironment($sEnv); + $oRunTimeEnvironment->CompileFrom(\utils::GetCurrentEnvironment()); + $oConfig->WriteToFile(); $sConfigFile = APPCONF.\utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE; MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv); $aMenuGroups = ApplicationMenu::GetMenuGroups(); - $this->assertNotEquals([], $aMenuGroups); - if (! is_null(static::$aPreviousEnvMenus)){ $this->assertEquals(static::$aPreviousEnvMenus, $aMenuGroups); } else { @@ -73,6 +73,13 @@ class MFCompilerMenuTest extends ItopTestCase { } static::$aPreviousEnvMenus = $aMenuGroups; - //$this->InvokeNonPublicMethod(MFCompiler::class, 'CompileThemes', $this->oMFCompiler, [$oBrandingNode, $this->sTmpDir]); + $aMenuCount = ApplicationMenu::GetMenusCount(); + + if (! is_null(static::$aPreviousEnvMenuCount)){ + $this->assertEquals(static::$aPreviousEnvMenuCount, $aMenuCount); + } else { + $this->assertNotEquals([], $aMenuCount); + } + static::$aPreviousEnvMenuCount = $aMenuCount; } }