protected function DoCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks = false) { $aAllClasses = array(); // flat list of classes // Determine the target modules for the MENUS // $aMenuNodes = array(); $aMenusByModule = array(); foreach ($this->oFactory->ListActiveChildNodes('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 // $sUserRightsModule = ''; $oUserRightsNode = $this->oFactory->GetNodes('user_rights')->item(0); if ($oUserRightsNode) { $sUserRightsModule = $oUserRightsNode->getAttribute('_created_in'); $this->Log("User Rights module found: {$sUserRightsModule}"); } // List root classes // $this->aRootClasses = array(); foreach ($this->oFactory->ListRootClasses() as $oClass) { $this->Log("Root class (with child classes): " . $oClass->getAttribute('id')); $this->aRootClasses[$oClass->getAttribute('id')] = $oClass; } // Compile, module by module // $aModules = $this->oFactory->GetLoadedModules(); foreach ($aModules as $foo => $oModule) { $sModuleName = $oModule->GetName(); $sModuleVersion = $oModule->GetVersion(); $sModuleRootDir = $oModule->GetRootDir(); if ($sModuleRootDir != '') { $sModuleRootDir = realpath($sModuleRootDir); $sRelativeDir = basename($sModuleRootDir); // Push the other module files SetupUtils::copydir($sModuleRootDir, $sTempTargetDir . '/' . $sRelativeDir, $bUseSymbolicLinks); } $sCompiledCode = ''; $oConstants = $this->oFactory->ListConstants($sModuleName); if ($oConstants->length > 0) { foreach ($oConstants as $oConstant) { $sCompiledCode .= $this->CompileConstant($oConstant) . "\n"; } } $oClasses = $this->oFactory->ListClasses($sModuleName); $iClassCount = $oClasses->length; if ($iClassCount == 0) { $this->Log("Found module without classes declared: {$sModuleName}"); } else { foreach ($oClasses as $oClass) { $sClass = $oClass->getAttribute("id"); $aAllClasses[] = $sClass; try { $sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); } catch (DOMFormatException $e) { throw new Exception("Failed to process class '{$sClass}', from '{$sModuleRootDir}': " . $e->getMessage()); } } } if (!array_key_exists($sModuleName, $aMenusByModule)) { $this->Log("Found module without menus declared: {$sModuleName}"); } else { $sCompiledCode .= <<<EOF // // Menus // global \$__comp_menus__; // ensure that the global variable is indeed global ! EOF; // Preliminary: determine parent menus not defined within the current module $aMenusToLoad = array(); $aParentMenus = array(); foreach ($aMenusByModule[$sModuleName] as $sMenuId) { $oMenuNode = $aMenuNodes[$sMenuId]; if ($sParent = $oMenuNode->GetChildText('parent', null)) { $aMenusToLoad[] = $sParent; $aParentMenus[] = $sParent; } // Note: the order matters: the parents must be defined BEFORE $aMenusToLoad[] = $sMenuId; } $aMenusToLoad = array_unique($aMenusToLoad); foreach ($aMenusToLoad as $sMenuId) { $oMenuNode = $aMenuNodes[$sMenuId]; if ($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 // 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 if (!in_array($oMenuNode->getAttribute("id"), $aParentMenus)) { // Discard empty menu groups continue; } } try { $sCompiledCode .= $this->CompileMenu($oMenuNode, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); } catch (DOMFormatException $e) { throw new Exception("Failed to process menu '{$sMenuId}', from '{$sModuleRootDir}': " . $e->getMessage()); } } } // User rights // if ($sModuleName == $sUserRightsModule) { $sCompiledCode .= $this->CompileUserRights($oUserRightsNode); } // Create (overwrite if existing) the compiled file // if (strlen($sCompiledCode) > 0) { // We have compiled something: write the result file // $sResultFile = $sTempTargetDir . '/' . $sRelativeDir . '/model.' . $sModuleName . '.php'; if (is_file($sResultFile)) { $this->Log("Updating {$sResultFile} for module {$sModuleName} in version {$sModuleVersion} ({$iClassCount} classes)"); } else { $sResultDir = dirname($sResultFile); if (!is_dir($sResultDir)) { $this->Log("Creating directory {$sResultDir}"); mkdir($sResultDir, 0777, true); } $this->Log("Creating {$sResultFile} for module {$sModuleName} in version {$sModuleVersion} ({$iClassCount} classes)"); } // Compile the module into a single file // $sId = $sModuleName; $sCurrDate = date(DATE_ISO8601); $sAuthor = 'iTop compiler'; $sLicence = 'http://opensource.org/licenses/AGPL-3.0'; $sFileHeader = <<<EOF <?php // // File generated by ... on the {$sCurrDate} // Please do not edit manually // /** * Classes and menus for {$sModuleName} (version {$sModuleVersion}) * * @author {$sAuthor} * @license {$sLicence} */ EOF; $ret = file_put_contents($sResultFile, $sFileHeader . $sCompiledCode); if ($ret === false) { $iLen = strlen($sFileHeader . $sCompiledCode); $fFree = @disk_free_space(dirname($sResultFile)); $aErr = error_get_last(); throw new Exception("Failed to write '{$sResultFile}'. Last error: '{$aErr['message']}', content to write: {$iLen} bytes, available free space on disk: {$fFree}."); } } else { $this->Log("Compilation of module {$sModuleName} in version {$sModuleVersion} produced not code at all. No file written."); } } // 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->ListActiveChildNodes('dictionaries', 'dictionary'); foreach ($oDictionaries as $oDictionaryNode) { $this->CompileDictionary($oDictionaryNode, $sTempTargetDir, $sFinalTargetDir); } // Compile the branding // $oBrandingNode = $this->oFactory->GetNodes('branding')->item(0); $this->CompileBranding($oBrandingNode, $sTempTargetDir, $sFinalTargetDir); }
protected function DoCompile($sTempTargetDir, $sFinalTargetDir, $oP = null, $bUseSymbolicLinks = false) { $aAllClasses = array(); // flat list of classes // Determine the target modules for the MENUS // $aMenuNodes = array(); $aMenusByModule = array(); 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 = array(); 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(); foreach ($aModules as $foo => $oModule) { $sModuleName = $oModule->GetName(); $sModuleVersion = $oModule->GetVersion(); $sModuleRootDir = $oModule->GetRootDir(); if ($sModuleRootDir != '') { $sModuleRootDir = realpath($sModuleRootDir); $sRelativeDir = basename($sModuleRootDir); // Push the other module files SetupUtils::copydir($sModuleRootDir, $sTempTargetDir . '/' . $sRelativeDir, $bUseSymbolicLinks); } $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 { foreach ($oClasses as $oClass) { $sClass = $oClass->getAttribute("id"); $aAllClasses[] = $sClass; try { $sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); } catch (DOMFormatException $e) { throw new Exception("Failed to process class '{$sClass}', from '{$sModuleRootDir}': " . $e->getMessage()); } } } 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 .= <<<EOF // // Menus // class {$sMenuCreationClass} extends ModuleHandlerAPI { \tpublic static function OnMenuCreation() \t{ \t\tglobal \$__comp_menus__; // ensure that the global variable is indeed global ! EOF; // Preliminary: determine parent menus not defined within the current module $aMenusToLoad = array(); $aParentMenus = array(); foreach ($aMenusByModule[$sModuleName] as $sMenuId) { $oMenuNode = $aMenuNodes[$sMenuId]; if ($sParent = $oMenuNode->GetChildText('parent', null)) { $aMenusToLoad[] = $sParent; $aParentMenus[] = $sParent; } // Note: the order matters: the parents must be defined BEFORE $aMenusToLoad[] = $sMenuId; } $aMenusToLoad = array_unique($aMenusToLoad); $aMenusForAll = array(); $aMenusForAdmins = array(); foreach ($aMenusToLoad as $sMenuId) { $oMenuNode = $aMenuNodes[$sMenuId]; if ($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 // 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 if (!in_array($oMenuNode->getAttribute("id"), $aParentMenus)) { // Discard empty menu groups continue; } } try { $aMenuLines = $this->CompileMenu($oMenuNode, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir, $oP); } catch (DOMFormatException $e) { throw new Exception("Failed to process menu '{$sMenuId}', from '{$sModuleRootDir}': " . $e->getMessage()); } if ($oMenuNode->GetChildText('enable_admin_only') == '1') { $aMenusForAdmins = array_merge($aMenusForAdmins, $aMenuLines); } else { $aMenusForAll = array_merge($aMenusForAll, $aMenuLines); } } $sIndent = "\t\t"; foreach ($aMenusForAll as $sPHPLine) { $sCompiledCode .= $sIndent . $sPHPLine . "\n"; } if (count($aMenusForAdmins) > 0) { $sCompiledCode .= $sIndent . "if (UserRights::IsAdministrator())\n"; $sCompiledCode .= $sIndent . "{\n"; foreach ($aMenusForAdmins as $sPHPLine) { $sCompiledCode .= $sIndent . "\t" . $sPHPLine . "\n"; } $sCompiledCode .= $sIndent . "}\n"; } $sCompiledCode .= <<<EOF \t} } // class {$sMenuCreationClass} EOF; } // User rights // if ($sModuleName == $sUserRightsModule) { $sCompiledCode .= $this->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 result file // $sResultFile = $sTempTargetDir . '/' . $sRelativeDir . '/model.' . $sModuleName . '.php'; if (is_file($sResultFile)) { $this->Log("Updating {$sResultFile} for module {$sModuleName} in version {$sModuleVersion} ({$iClassCount} classes)"); } else { $sResultDir = dirname($sResultFile); if (!is_dir($sResultDir)) { $this->Log("Creating directory {$sResultDir}"); mkdir($sResultDir, 0777, true); } $this->Log("Creating {$sResultFile} for module {$sModuleName} in version {$sModuleVersion} ({$iClassCount} classes)"); } // Compile the module into a single file // $sId = $sModuleName; $sCurrDate = date(DATE_ISO8601); $sAuthor = 'iTop compiler'; $sLicence = 'http://opensource.org/licenses/AGPL-3.0'; $sFileHeader = <<<EOF <?php // // File generated by ... on the {$sCurrDate} // Please do not edit manually // /** * Classes and menus for {$sModuleName} (version {$sModuleVersion}) * * @author {$sAuthor} * @license {$sLicence} */ EOF; $ret = file_put_contents($sResultFile, $sFileHeader . $sCompiledCode); if ($ret === false) { $iLen = strlen($sFileHeader . $sCompiledCode); $fFree = @disk_free_space(dirname($sResultFile)); $aErr = error_get_last(); throw new Exception("Failed to write '{$sResultFile}'. Last error: '{$aErr['message']}', content to write: {$iLen} bytes, available free space on disk: {$fFree}."); } } else { $this->Log("Compilation of module {$sModuleName} in version {$sModuleVersion} produced not code at all. No file written."); } } // 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'); foreach ($oDictionaries as $oDictionaryNode) { $this->CompileDictionary($oDictionaryNode, $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 $this->CompileModuleDesigns($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); }
protected static function DoCopy($aCopies) { $aReports = array(); foreach ($aCopies as $aCopy) { $sSource = $aCopy['source']; $sDestination = APPROOT . $aCopy['destination']; SetupUtils::builddir($sDestination); SetupUtils::tidydir($sDestination); SetupUtils::copydir($sSource, $sDestination); $aReports[] = "'{$aCopy['source']}' to '{$aCopy['destination']}' (OK)"; } if (count($aReports) > 0) { $sReport = "Copies: " . count($aReports) . ': ' . implode('; ', $aReports); } else { $sReport = "No file copy"; } return $sReport; }