Ver código fonte

New way to compile the dictionaries, allowing for incremental modification via XML

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@2712 a333f486-631f-4898-b8df-5754b55c2be0
romainq 12 anos atrás
pai
commit
d6047dc73e
3 arquivos alterados com 183 adições e 12 exclusões
  1. 11 4
      core/config.class.inc.php
  2. 58 6
      setup/compiler.class.inc.php
  3. 114 2
      setup/modelfactory.class.inc.php

+ 11 - 4
core/config.class.inc.php

@@ -1570,10 +1570,6 @@ class Config
 					{
 						$aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice']));
 					}
-					if (isset($aModuleInfo['dictionary']))
-					{
-						$aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary']));
-					}
 					if (isset($aModuleInfo['settings']))
 					{
 						list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
@@ -1609,6 +1605,17 @@ class Config
 			$this->SetAppModules($aAppModules);
 			$this->SetDataModels($aDataModels);
 			$this->SetWebServiceCategories($aWebServiceCategories);
+
+			// Scan dictionaries
+			//
+			if (!is_null($sModulesDir))
+			{
+				foreach(glob(APPROOT.$sModulesDir.'/dictionaries/*.dict.php') as $sFilePath)
+				{
+					$sFile = basename($sFilePath);
+					$aDictionaries[] = $sModulesDir.'/dictionaries/'.$sFile;
+				}
+			}
 			$this->SetDictionaries($aDictionaries);
 		}
 	}

+ 58 - 6
setup/compiler.class.inc.php

@@ -257,7 +257,21 @@ EOF;
 			{
 					$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 = $sTargetDir.'/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, $sTargetDir);
 		}
 	}
 
@@ -451,10 +465,18 @@ EOF;
 	/**
 	 * Adds quotes and escape characters
 	 */	 	
-	protected function QuoteForPHP($sStr)
+	protected function QuoteForPHP($sStr, $bSimpleQuotes = false)
 	{
-		$sEscaped = str_replace(array('\\', '"', "\n"), array('\\\\', '\\"', '\\n'), $sStr);
-		$sRet = '"'.$sEscaped.'"';
+		if ($bSimpleQuotes)
+		{
+			$sEscaped = str_replace(array('\\', "'"), array('\\\\', "\\'"), $sStr);
+			$sRet = "'$sEscaped'";
+		}
+		else
+		{
+			$sEscaped = str_replace(array('\\', '"', "\n"), array('\\\\', '\\"', '\\n'), $sStr);
+			$sRet = '"'.$sEscaped.'"';
+		}
 		return $sRet;
 	}
 
@@ -1408,8 +1430,38 @@ EOF;
 	return $sPHP;
 	} // function CompileUserRights
 
-}
+	protected function CompileDictionary($oDictionaryNode, $sTargetDir)
+	{
+		$sLang = $oDictionaryNode->getAttribute('id');
+		$sEnglishLanguageDesc = $oDictionaryNode->GetChildText('english_description');
+		$sLocalizedLanguageDesc = $oDictionaryNode->GetChildText('localized_description');
 
+		$aEntriesPHP = array();
+		$oEntries = $oDictionaryNode->GetUniqueElement('entries');
+		foreach($oEntries->getElementsByTagName('entry') as $oEntry)
+		{
+			$sStringCode = $oEntry->getAttribute('id');
+			$sValue = $oEntry->GetText();
+			$aEntriesPHP[] = "\t'$sStringCode' => ".self::QuoteForPHP($sValue, true).",";
+		}
+		$sEntriesPHP = implode("\n", $aEntriesPHP);
 
+		$sEscEnglishLanguageDesc = self::QuoteForPHP($sEnglishLanguageDesc);
+		$sEscLocalizedLanguageDesc = self::QuoteForPHP($sLocalizedLanguageDesc);
+		$sPHPDict =
+<<<EOF
+<?php
+//
+// Dictionary built by the compiler for the language "$sLang"
+//
+Dict::Add('$sLang', $sEscEnglishLanguageDesc, $sEscLocalizedLanguageDesc, array(
+$sEntriesPHP
+));
+EOF;
+		$sSafeLang = str_replace(' ', '-', strtolower(trim($sLang)));
+		$sDictFile = $sTargetDir.'/dictionaries/'.$sSafeLang.'.dict.php';
+		file_put_contents($sDictFile, $sPHPDict);
+	}
+}
 
-?>
+?>

+ 114 - 2
setup/modelfactory.class.inc.php

@@ -111,6 +111,24 @@ class MFModule
 	{
 		return array();
 	}
+	
+	public function GetDictionaryFiles()
+	{
+		$aDictionaries = array();
+		if ($hDir = opendir($this->sRootDir))
+		{
+			while (($sFile = readdir($hDir)) !== false)
+			{
+				$aMatches = array();
+				if (preg_match("/^[^\\.]+.dict.".$this->sName.".php$/i", $sFile, $aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
+				{
+					$aDictionaries[] = $this->sRootDir.'/'.$sFile;
+				}
+			}
+			closedir($hDir);
+		}
+		return $aDictionaries;		
+	}
 }
 
 /**
@@ -125,15 +143,20 @@ class ModelFactory
 	protected $oModules;
 	protected $oClasses;
 	protected $oMenus;
+	protected $oDictionaries;
 	static protected $aLoadedClasses;
 	static protected $aWellKnownParents = array('DBObject', 'CMDBObject','cmdbAbstractObject');
 //	static protected $aWellKnownMenus = array('DataAdministration', 'Catalogs', 'ConfigManagement', 'Contact', 'ConfigManagementCI', 'ConfigManagement:Shortcuts', 'ServiceManagement');
 	static protected $aLoadedModules;
 	static protected $aLoadErrors;
-
+	protected $aDict;
+	protected $aDictKeys;
+	
 	
 	public function __construct($aRootDirs, $aRootNodeExtensions = array())
 	{
+		$this->aDict = array();
+		$this->aDictKeys = array();
 		$this->aRootDirs = $aRootDirs;
 		$this->oDOMDocument = new MFDocument();
 		$this->oRoot = $this->oDOMDocument->CreateElement('itop_design');
@@ -143,6 +166,9 @@ class ModelFactory
 		$this->oRoot->AppendChild($this->oModules);
 		$this->oClasses = $this->oDOMDocument->CreateElement('classes');
 		$this->oRoot->AppendChild($this->oClasses);
+		$this->oDictionaries = $this->oDOMDocument->CreateElement('dictionaries');
+		$this->oRoot->AppendChild($this->oDictionaries);
+		
 		foreach (self::$aWellKnownParents as $sWellKnownParent)
 		{
 			$this->AddWellKnownParent($sWellKnownParent);
@@ -353,6 +379,65 @@ class ModelFactory
 				$oDeltaRoot = $oDocument->childNodes->item(0);
 				$this->LoadDelta($oDocument, $oDeltaRoot, $this->oDOMDocument);
 			}
+			
+			$aDictionaries = $oModule->GetDictionaryFiles();
+			
+			try
+			{
+				$this->ResetTempDictionary();
+				foreach($aDictionaries as $sPHPFile)
+				{
+					$sDictFileContents = file_get_contents($sPHPFile);
+					$sDictFileContents = str_replace(array('<'.'?'.'php', '?'.'>'), '', $sDictFileContents);
+					$sDictFileContents = str_replace('Dict::Add', '$this->AddToTempDictionary', $sDictFileContents);
+					eval($sDictFileContents);
+				}
+				
+				foreach ($this->aDict as $sLanguageCode => $aDictDefinition)
+				{
+					$oNodes = $this->GetNodeById('dictionary', $sLanguageCode, $this->oDictionaries);
+					if ($oNodes->length == 0)
+					{
+						$oXmlDict = $this->oDOMDocument->CreateElement('dictionary');
+						$oXmlDict->setAttribute('id', $sLanguageCode);
+						$this->oDictionaries->AddChildNode($oXmlDict);
+						$oXmlEntries = $this->oDOMDocument->CreateElement('english_description', $aDictDefinition['english_description']);
+						$oXmlDict->AppendChild($oXmlEntries);
+						$oXmlEntries = $this->oDOMDocument->CreateElement('localized_description', $aDictDefinition['localized_description']);
+						$oXmlDict->AppendChild($oXmlEntries);
+						$oXmlEntries = $this->oDOMDocument->CreateElement('entries');
+						$oXmlDict->AppendChild($oXmlEntries);
+					}
+					else
+					{
+						$oXmlDict = $oNodes->item(0);
+						$oXmlEntries = $oXmlDict->GetUniqueElement('entries');
+					}
+							
+					foreach ($aDictDefinition['entries'] as $sCode => $sLabel)
+					{
+						
+						$oXmlEntry = $this->oDOMDocument->CreateElement('entry');
+						$oXmlEntry->setAttribute('id', $sCode);
+						$oXmlValue = $this->oDOMDocument->CreateCDATASection($sLabel);
+						$oXmlEntry->appendChild($oXmlValue);
+						if (array_key_exists($sLanguageCode, $this->aDictKeys) && array_key_exists($sCode, $this->aDictKeys[$sLanguageCode]))
+						{
+							$oXmlEntries->RedefineChildNode($oXmlEntry);
+						}
+						else 
+						{
+							$oXmlEntries->appendChild($oXmlEntry);
+						}
+						$this->aDictKeys[$sLanguageCode][$sCode] = true;
+					}
+				}	 				
+			}
+			catch(Exception $e)
+			{
+				throw new Exception('Failed to load dictionary file "'.$sPHPFile.'", reason: '.$e->getMessage());
+			}
+			
 		}
 		catch(Exception $e)
 		{
@@ -366,6 +451,33 @@ class ModelFactory
 	}
 
 	/**
+	 * Collects the PHP Dict entries into the ModelFactory for transforming the dictionary into an XML structure
+	 * @param string $sLanguageCode The language code
+	 * @param string $sEnglishLanguageDesc English description of the language (unused but kept for API compatibility)
+	 * @param string $sLocalizedLanguageDesc Localized description of the language (unused but kept for API compatibility)
+	 * @param hash $aEntries The entries to load: string_code => translation
+	 */
+	protected function AddToTempDictionary($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
+	{
+		$this->aDict[$sLanguageCode]['english_description'] = $sEnglishLanguageDesc;
+		$this->aDict[$sLanguageCode]['localized_description'] = $sLocalizedLanguageDesc;
+		if (!array_key_exists('entries', $this->aDict[$sLanguageCode]))
+		{
+			$this->aDict[$sLanguageCode]['entries'] = array();
+		}
+
+		foreach($aEntries as $sKey => $sValue)
+		{
+			$this->aDict[$sLanguageCode]['entries'][$sKey] = $sValue;
+		}
+	}
+	
+	protected function ResetTempDictionary()
+	{
+		$this->aDict = array();
+	}
+	
+	/**
 	 *	XML load errors (XML format and validation)
 	 */	
 	function HasLoadErrors()
@@ -568,7 +680,7 @@ class ModelFactory
 	
 	public function GetClassXMLTemplate($sName, $sIcon)
 	{
-		$sHeader = '<?xml version="1.0" encoding="utf-8"?'.'>';
+		$sHeader = '<?'.'xml version="1.0" encoding="utf-8"?'.'>';
 		return
 <<<EOF
 $sHeader