|
@@ -108,6 +108,11 @@ class MFModule extends MFItem
|
|
|
return $this->sRootDir;
|
|
|
}
|
|
|
|
|
|
+ public function GetModuleDir()
|
|
|
+ {
|
|
|
+ return basename($this->sRootDir);
|
|
|
+ }
|
|
|
+
|
|
|
public function GetDataModelFiles()
|
|
|
{
|
|
|
return $this->aDataModels;
|
|
@@ -142,6 +147,11 @@ class MFWorkspace extends MFModule
|
|
|
{
|
|
|
return $this->sRootDir.'/workspace.xml';
|
|
|
}
|
|
|
+
|
|
|
+ public function GetName()
|
|
|
+ {
|
|
|
+ return ''; // The workspace itself has no name so that objects created inside it retain their original module's name
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -330,7 +340,7 @@ class ModelFactory
|
|
|
$sOperation = $aClassData['node']->getAttribute('_operation');
|
|
|
switch($sOperation)
|
|
|
{
|
|
|
- case 'created':
|
|
|
+ case 'added':
|
|
|
case '':
|
|
|
if (in_array($aClassData['parent'], self::$aWellKnownParents))
|
|
|
{
|
|
@@ -353,7 +363,7 @@ class ModelFactory
|
|
|
|
|
|
case 'modified':
|
|
|
unset($aClasses[$sClassName]);
|
|
|
- $this->AlterClass($aClassData['node'], $sModuleName);
|
|
|
+ $this->AlterClass($sClassName, $aClassData['node']);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -367,7 +377,7 @@ class ModelFactory
|
|
|
$sOperation = $aClassData['node']->getAttribute('_operation');
|
|
|
switch($sOperation)
|
|
|
{
|
|
|
- case 'created':
|
|
|
+ case 'added':
|
|
|
case '':
|
|
|
// Add the class as a new root class
|
|
|
$this->AddClass($aClassData['node'], $sModuleName);
|
|
@@ -380,7 +390,7 @@ class ModelFactory
|
|
|
|
|
|
case 'modified':
|
|
|
//@@TODO Handle the modification of a class here
|
|
|
- $this->AlterClass($aClassData['node'], $sModuleName);
|
|
|
+ $this->AlterClass($sClassName, $aClassData['node']);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -406,6 +416,17 @@ class ModelFactory
|
|
|
return $aModules;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ function GetModule($sModuleName)
|
|
|
+ {
|
|
|
+ foreach(self::$aLoadedModules as $oModule)
|
|
|
+ {
|
|
|
+ if ($oModule->GetName() == $sModuleName) return $oModule;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Check if the class specified by the given node already exists in the loaded DOM
|
|
|
* @param DOMNode $oClassNode The node corresponding to the class to load
|
|
@@ -442,7 +463,7 @@ class ModelFactory
|
|
|
* @param string $sModuleName The name of the module in which this class is declared
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- protected function AddClass(DOMNode $oClassNode, $sModuleName)
|
|
|
+ public function AddClass(DOMNode $oClassNode, $sModuleName)
|
|
|
{
|
|
|
if ($oClassNode->hasAttribute('name'))
|
|
|
{
|
|
@@ -469,7 +490,10 @@ class ModelFactory
|
|
|
// The class is a subclass of a class already loaded, add it under
|
|
|
self::$aLoadedClasses[$sClassName] = $this->oDOMDocument->ImportNode($oClassNode, true /* bDeep */);
|
|
|
self::$aLoadedClasses[$sClassName]->SetAttribute('_operation', 'added');
|
|
|
- self::$aLoadedClasses[$sClassName]->SetAttribute('_created_in', $sModuleName);
|
|
|
+ if ($sModuleName != '')
|
|
|
+ {
|
|
|
+ self::$aLoadedClasses[$sClassName]->SetAttribute('_created_in', $sModuleName);
|
|
|
+ }
|
|
|
self::$aLoadedClasses[$sParentClass]->AppendChild(self::$aLoadedClasses[$sClassName]);
|
|
|
$bNothingLoaded = false;
|
|
|
}
|
|
@@ -478,7 +502,10 @@ class ModelFactory
|
|
|
// Add the class as a new root class
|
|
|
self::$aLoadedClasses[$sClassName] = $this->oDOMDocument->ImportNode($oClassNode, true /* bDeep */);
|
|
|
self::$aLoadedClasses[$sClassName]->SetAttribute('_operation', 'added');
|
|
|
- self::$aLoadedClasses[$sClassName]->SetAttribute('_created_in', $sModuleName);
|
|
|
+ if ($sModuleName != '')
|
|
|
+ {
|
|
|
+ self::$aLoadedClasses[$sClassName]->SetAttribute('_created_in', $sModuleName);
|
|
|
+ }
|
|
|
$this->oClasses->AppendChild(self::$aLoadedClasses[$sClassName]);
|
|
|
}
|
|
|
else
|
|
@@ -498,82 +525,165 @@ class ModelFactory
|
|
|
{
|
|
|
throw new Exception("ModelFactory::RemoveClass: Cannot remove the non existing class $sClass");
|
|
|
}
|
|
|
- self::$aLoadedClasses[$sClass]->SetAttribute('_operation', 'removed');
|
|
|
+ $oClassNode = self::$aLoadedClasses[$sClass];
|
|
|
+ if ($oClassNode->getAttribute('_operation') == 'added')
|
|
|
+ {
|
|
|
+ $oClassNode->parentNode->RemoveChild($oClassNode);
|
|
|
+ unset(self::$aLoadedClasses[$sClass]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ self::$aLoadedClasses[$sClass]->SetAttribute('_operation', 'removed');
|
|
|
+ //TODO: also mark as removed the child classes
|
|
|
+ }
|
|
|
|
|
|
- //TODO: also mark as removed the child classes
|
|
|
}
|
|
|
|
|
|
- public function AlterClass(DOMNode $oClassNode, $sModuleName)
|
|
|
+ public function AlterClass($sClassName, DOMNode $oClassNode)
|
|
|
{
|
|
|
- if ($oClassNode->hasAttribute('name'))
|
|
|
+ $sOriginalName = $sClassName;
|
|
|
+ if ($this->ClassNameExists($sClassName))
|
|
|
{
|
|
|
- $sClassName = $oClassNode->GetAttribute('name');
|
|
|
+ $oDestNode = self::$aLoadedClasses[$sClassName];
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- throw new Exception('ModelFactory::AddClass: Cannot alter a class with no name');
|
|
|
+ $sOriginalName = $oClassNode->getAttribute('_original_name');
|
|
|
+ if ($this->ClassNameExists($sOriginalName))
|
|
|
+ {
|
|
|
+ // Class was renamed !
|
|
|
+ $oDestNode = self::$aLoadedClasses[$sOriginalName];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ throw new Exception("ModelFactory::AddClass: Cannot alter the non-existing class $sClassName / $sOriginalName");
|
|
|
+ }
|
|
|
}
|
|
|
- if (!$this->ClassExists($oClassNode))
|
|
|
+ $this->_priv_AlterNode($oDestNode, $oClassNode);
|
|
|
+ $sClassName = $oDestNode->getAttribute('name');
|
|
|
+ if ($sOriginalName != $sClassName)
|
|
|
{
|
|
|
- throw new Exception("ModelFactory::AddClass: Cannot later the non-existing class $sClassName");
|
|
|
+ unset(self::$aLoadedClasses[$sOriginalName]);
|
|
|
+ self::$aLoadedClasses[$sClassName] = $oDestNode;
|
|
|
}
|
|
|
- $this->_priv_AlterNode(self::$aLoadedClasses[$sClassName], $oClassNode);
|
|
|
+ $this->_priv_SetFlag($oDestNode, 'modified');
|
|
|
}
|
|
|
|
|
|
protected function _priv_AlterNode(DOMNode $oNode, DOMNode $oDeltaNode)
|
|
|
{
|
|
|
foreach ($oDeltaNode->attributes as $sName => $oAttrNode)
|
|
|
{
|
|
|
+ $sCurrentValue = $oNode->getAttribute($sName);
|
|
|
+ $sNewValue = $oAttrNode->value;
|
|
|
$oNode->setAttribute($sName, $oAttrNode->value);
|
|
|
}
|
|
|
|
|
|
- foreach($oDeltaNode->childNodes as $oChildNode)
|
|
|
+ $aSrcChildNodes = $oNode->childNodes;
|
|
|
+ foreach($oDeltaNode->childNodes as $index => $oChildNode)
|
|
|
{
|
|
|
- $sOperation = $oChildNode->getAttribute('_operation');
|
|
|
- $sPath = $oChildNode->tagName;
|
|
|
- $sName = $oChildNode->getAttribute('name');
|
|
|
- if ($sName != '')
|
|
|
- {
|
|
|
- $sPath .= "[@name='$sName']";
|
|
|
- }
|
|
|
- switch($sOperation)
|
|
|
+ if (!$oChildNode instanceof DOMElement)
|
|
|
{
|
|
|
- case 'removed':
|
|
|
- $oToRemove = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
- if ($oToRemove != null)
|
|
|
+ // Text or CData nodes are treated by position
|
|
|
+ $sOperation = $oChildNode->parentNode->getAttribute('_operation');
|
|
|
+ switch($sOperation)
|
|
|
{
|
|
|
- $this->_priv_SetFlag($oToRemove, 'removed');
|
|
|
+ case 'removed':
|
|
|
+ // ???
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'modified':
|
|
|
+ case 'replaced':
|
|
|
+ case 'added':
|
|
|
+ $oNewNode = $this->oDOMDocument->importNode($oChildNode);
|
|
|
+ $oSrcChildNode = $aSrcChildNodes->item($index);
|
|
|
+ if ($oSrcChildNode)
|
|
|
+ {
|
|
|
+ $oNode->replaceChild($oNewNode, $oSrcChildNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oNode->appendChild($oNewNode);
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case '':
|
|
|
+ // Do nothing
|
|
|
}
|
|
|
- break;
|
|
|
-
|
|
|
- case 'modified':
|
|
|
- $oToModify = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
- if ($oToModify != null)
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $sOperation = $oChildNode->getAttribute('_operation');
|
|
|
+ $sPath = $oChildNode->tagName;
|
|
|
+ $sName = $oChildNode->getAttribute('name');
|
|
|
+ if ($sName != '')
|
|
|
{
|
|
|
- $this->_priv_AlterNode($oToModify, $oChildNode);
|
|
|
+ $sPath .= "[@name='$sName']";
|
|
|
}
|
|
|
- else
|
|
|
+ switch($sOperation)
|
|
|
{
|
|
|
- throw new Exception("Cannot modify the non-existing node '$sPath' in '".$oNode->getNodePath()."'");
|
|
|
+ case 'removed':
|
|
|
+ $oToRemove = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
+ if ($oToRemove != null)
|
|
|
+ {
|
|
|
+ $this->_priv_SetFlag($oToRemove, 'removed');
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'modified':
|
|
|
+ $oToModify = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
+ if ($oToModify != null)
|
|
|
+ {
|
|
|
+ $this->_priv_AlterNode($oToModify, $oChildNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ throw new Exception("Cannot modify the non-existing node '$sPath' in '".$oNode->getNodePath()."'");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'replaced':
|
|
|
+ $oNewNode = $this->oDOMDocument->importNode($oChildNode, true); // Import the node and its child nodes
|
|
|
+ $oToModify = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
+ $oNode->replaceChild($oNewNode, $oToModify);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'added':
|
|
|
+ $oNewNode = $this->oDOMDocument->importNode($oChildNode);
|
|
|
+ $oNode->appendChild($oNewNode);
|
|
|
+ $this->_priv_SetFlag($oNewNode, 'added');
|
|
|
+ break;
|
|
|
+
|
|
|
+ case '':
|
|
|
+ // Do nothing
|
|
|
}
|
|
|
- break;
|
|
|
-
|
|
|
- case 'replaced':
|
|
|
- $oNewNode = $this->oDOMDocument->importNode($oChildNode, true); // Import the node and its child nodes
|
|
|
- $oToModify = $this->_priv_GetNodes($sPath, $oNode)->item(0);
|
|
|
- $oNode->replaceChild($oNewNode, $oToModify);
|
|
|
- break;
|
|
|
-
|
|
|
- case 'created':
|
|
|
- $oNewNode = $this->oDOMDocument->importNode($oChildNode);
|
|
|
- $oNode->appendChild($oNewNode);
|
|
|
- $this->_priv_SetFlag($oNewNode, 'created');
|
|
|
- break;
|
|
|
-
|
|
|
- case '':
|
|
|
- // Do nothing
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function GetClassXMLTemplate($sName, $sIcon)
|
|
|
+ {
|
|
|
+ return
|
|
|
+<<<EOF
|
|
|
+<?xml version="1.0" encoding="utf-8"?>
|
|
|
+<class name="$sName" parent="" db_table="" category="" abstract="" key_type="autoincrement" db_key_field="id" db_final_class_field="finalclass">
|
|
|
+ <properties>
|
|
|
+ <comment/>
|
|
|
+ <naming format=""><attributes/></naming>
|
|
|
+ <reconciliation><attributes/></reconciliation>
|
|
|
+ <display_template/>
|
|
|
+ <icon>$sIcon</icon>
|
|
|
+ </properties>
|
|
|
+ <fields/>
|
|
|
+ <methods/>
|
|
|
+ <presentation>
|
|
|
+ <details><items/></details>
|
|
|
+ <search><items/></search>
|
|
|
+ <list><items/></list>
|
|
|
+ </presentation>
|
|
|
+</class>
|
|
|
+EOF
|
|
|
+ ;
|
|
|
}
|
|
|
/**
|
|
|
* List all classes from the DOM, for a given module
|
|
@@ -591,6 +701,22 @@ class ModelFactory
|
|
|
return $this->_priv_GetNodes($sXPath);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * List all classes from the DOM, for a given module
|
|
|
+ * @param string $sModuleNale
|
|
|
+ * @param bool $bFlattenLayers
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public function ListAllClasses($bFlattenLayers = true)
|
|
|
+ {
|
|
|
+ $sXPath = "//class";
|
|
|
+ if ($bFlattenLayers)
|
|
|
+ {
|
|
|
+ $sXPath = "//class[@_operation!='removed']";
|
|
|
+ }
|
|
|
+ return $this->_priv_GetNodes($sXPath);
|
|
|
+ }
|
|
|
+
|
|
|
public function GetClass($sClassName, $bFlattenLayers = true)
|
|
|
{
|
|
|
if (!$this->ClassNameExists($sClassName))
|
|
@@ -609,6 +735,34 @@ class ModelFactory
|
|
|
return $oClassNode;
|
|
|
}
|
|
|
|
|
|
+ public function GetField($sClassName, $sAttCode, $bFlattenLayers = true)
|
|
|
+ {
|
|
|
+ if (!$this->ClassNameExists($sClassName))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ $oClassNode = self::$aLoadedClasses[$sClassName];
|
|
|
+ if ($bFlattenLayers)
|
|
|
+ {
|
|
|
+ $sOperation = $oClassNode->getAttribute('_operation');
|
|
|
+ if ($sOperation == 'removed')
|
|
|
+ {
|
|
|
+ $oClassNode = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $sXPath = "fields/field[@name='$sAttCode']";
|
|
|
+ if ($bFlattenLayers)
|
|
|
+ {
|
|
|
+ $sXPath = "fields/field[(@name='$sAttCode' and (not(@_operation) or @_operation!='removed'))]";
|
|
|
+ }
|
|
|
+ $oFieldNode = $this->_priv_GetNodes($sXPath, $oClassNode)->item(0);
|
|
|
+ if (($oFieldNode == null) && ($oClassNode->getAttribute('parent') != ''))
|
|
|
+ {
|
|
|
+ return $this->GetField($oClassNode->getAttribute('parent'), $sAttCode, $bFlattenLayers);
|
|
|
+ }
|
|
|
+ return $oFieldNode;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* List all classes from the DOM
|
|
|
* @param bool $bFlattenLayers
|
|
@@ -631,7 +785,7 @@ class ModelFactory
|
|
|
$this->_priv_AlterField($oNewField, $sFieldType, $sSQL, $defaultValue, $bIsNullAllowed, $aExtraParams);
|
|
|
$oFields = $oClassNode->getElementsByTagName('fields')->item(0);
|
|
|
$oFields->AppendChild($oNewField);
|
|
|
- $this->_priv_SetFlag($oNewField, 'created');
|
|
|
+ $this->_priv_SetFlag($oNewField, 'added');
|
|
|
}
|
|
|
|
|
|
public function RemoveField(DOMNode $oClassNode, $sFieldCode)
|
|
@@ -640,8 +794,16 @@ class ModelFactory
|
|
|
$oFieldNodes = $this->_priv_GetNodes($sXPath, $oClassNode);
|
|
|
if (is_object($oFieldNodes) && (is_object($oFieldNodes->item(0))))
|
|
|
{
|
|
|
- //@@TODO: if the field was 'created' => then really delete it
|
|
|
- $this->_priv_SetFlag($oFieldNodes->item(0), 'removed');
|
|
|
+ $oFieldNode = $oFieldNodes->item(0);
|
|
|
+ $sOpCode = $oFieldNode->getAttribute('_operation');
|
|
|
+ if ($oFieldNode->getAttribute('_operation') == 'added')
|
|
|
+ {
|
|
|
+ $oFieldNode->parentNode->removeChild($oFieldNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $this->_priv_SetFlag($oFieldNode, 'removed');
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -651,8 +813,19 @@ class ModelFactory
|
|
|
$oFieldNodes = $this->_priv_GetNodes($sXPath, $oClassNode);
|
|
|
if (is_object($oFieldNodes) && (is_object($oFieldNodes->item(0))))
|
|
|
{
|
|
|
- //@@TODO: if the field was 'created' => then let it as 'created'
|
|
|
- $this->_priv_SetFlag($oFieldNodes->item(0), 'modified');
|
|
|
+ $oFieldNode = $oFieldNodes->item(0);
|
|
|
+ //@@TODO: if the field was 'added' => then let it as 'added'
|
|
|
+ $sOpCode = $oFieldNode->getAttribute('_operation');
|
|
|
+ switch($sOpCode)
|
|
|
+ {
|
|
|
+ case 'added':
|
|
|
+ case 'modified':
|
|
|
+ // added or modified, let it as it is
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ $this->_priv_SetFlag($oFieldNodes->item(0), 'modified');
|
|
|
+ }
|
|
|
$this->_priv_AlterField($oFieldNodes->item(0), $sFieldType, $sSQL, $defaultValue, $bIsNullAllowed, $aExtraParams);
|
|
|
}
|
|
|
}
|
|
@@ -660,14 +833,34 @@ class ModelFactory
|
|
|
protected function _priv_AlterField(DOMNode $oFieldNode, $sFieldType, $sSQL, $defaultValue, $bIsNullAllowed, $aExtraParams)
|
|
|
{
|
|
|
switch($sFieldType)
|
|
|
- {
|
|
|
+ {
|
|
|
+ case 'Blob':
|
|
|
+ case 'Boolean':
|
|
|
+ case 'CaseLog':
|
|
|
+ case 'Deadline':
|
|
|
+ case 'Duration':
|
|
|
+ case 'EmailAddress':
|
|
|
+ case 'EncryptedString':
|
|
|
+ case 'HTML':
|
|
|
+ case 'IPAddress':
|
|
|
+ case 'LongText':
|
|
|
+ case 'OQL':
|
|
|
+ case 'OneWayPassword':
|
|
|
+ case 'Password':
|
|
|
+ case 'Percentage':
|
|
|
case 'String':
|
|
|
case 'Text':
|
|
|
- case 'IPAddress':
|
|
|
- case 'EmailAddress':
|
|
|
- case 'Blob':
|
|
|
- break;
|
|
|
-
|
|
|
+ case 'Text':
|
|
|
+ case 'TemplateHTML':
|
|
|
+ case 'TemplateString':
|
|
|
+ case 'TemplateText':
|
|
|
+ case 'URL':
|
|
|
+ case 'Date':
|
|
|
+ case 'DateTime':
|
|
|
+ case 'Decimal':
|
|
|
+ case 'Integer':
|
|
|
+ break;
|
|
|
+
|
|
|
case 'ExternalKey':
|
|
|
$this->_priv_AddFieldAttribute($oFieldNode, 'target_class', $aExtraParams);
|
|
|
// Fall through
|
|
@@ -740,7 +933,7 @@ class ModelFactory
|
|
|
protected function _priv_SetFieldValues($oFieldNode, $aExtraParams)
|
|
|
{
|
|
|
$aVals = array_key_exists('values', $aExtraParams) ? $aExtraParams['values'] : '';
|
|
|
- $oValues = $oFieldNode->getElementByTagName('values')->item(0);
|
|
|
+ $oValues = $oFieldNode->getElementsByTagName('values')->item(0);
|
|
|
|
|
|
// No dependencies before, and no dependencies to add, exit
|
|
|
if (($oValues == null) && ($aVals == '')) return;
|
|
@@ -756,14 +949,69 @@ class ModelFactory
|
|
|
foreach($aVals as $sValue)
|
|
|
{
|
|
|
$oVal = $this->oDOMDocument->createElement('value', $sValue);
|
|
|
- $oValues->addChild($oVal);
|
|
|
+ $oValues->appendChild($oVal);
|
|
|
}
|
|
|
- $oFieldNode->addChild($oValues);
|
|
|
+ $oFieldNode->appendChild($oValues);
|
|
|
}
|
|
|
|
|
|
- protected function _priv_SetFlag($oNode, $sFlagValue)
|
|
|
+ public function SetPresentation(DOMNode $oClassNode, $sPresentationCode, $aPresentation)
|
|
|
+ {
|
|
|
+ $oPresentation = $oClassNode->getElementsByTagName('presentation')->item(0);
|
|
|
+ if (!is_object($oPresentation))
|
|
|
+ {
|
|
|
+ $oPresentation = $this->oDOMDocument->createElement('presentation');
|
|
|
+ $oClassNode->appendChild($oPresentation);
|
|
|
+ }
|
|
|
+ $oZlist = $oPresentation->getElementsByTagName($sPresentationCode)->item(0);
|
|
|
+ if (is_object($oZlist))
|
|
|
+ {
|
|
|
+ // Remove the previous Zlist
|
|
|
+ $oPresentation->removeChild($oZlist);
|
|
|
+ }
|
|
|
+ // Create the ZList anew
|
|
|
+ $oZlist = $this->oDOMDocument->createElement($sPresentationCode);
|
|
|
+ $oPresentation->appendChild($oZlist);
|
|
|
+ $this->AddZListItem($oZlist, $aPresentation);
|
|
|
+ $this->_priv_SetFlag($oZlist, 'replaced');
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function AddZListItem($oXMLNode, $value)
|
|
|
+ {
|
|
|
+ if (is_array($value))
|
|
|
+ {
|
|
|
+ $oXmlItems = $this->oDOMDocument->CreateElement('items');
|
|
|
+ $oXMLNode->appendChild($oXmlItems);
|
|
|
+
|
|
|
+ foreach($value as $key => $item)
|
|
|
+ {
|
|
|
+ $oXmlItem = $this->oDOMDocument->CreateElement('item');
|
|
|
+ $oXmlItems->appendChild($oXmlItem);
|
|
|
+
|
|
|
+ if (is_string($key))
|
|
|
+ {
|
|
|
+ $oXmlItem->SetAttribute('key', $key);
|
|
|
+ }
|
|
|
+ $this->AddZListItem($oXmlItem, $item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oXmlText = $this->oDOMDocument->CreateTextNode((string) $value);
|
|
|
+ $oXMLNode->appendChild($oXmlText);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function _priv_SetFlag($oNode, $sFlagValue)
|
|
|
{
|
|
|
- $oNode->setAttribute('_operation', $sFlagValue);
|
|
|
+ $sPreviousFlag = $oNode->getAttribute('_operation');
|
|
|
+ if ($sPreviousFlag == 'added')
|
|
|
+ {
|
|
|
+ // Do nothing ??
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oNode->setAttribute('_operation', $sFlagValue);
|
|
|
+ }
|
|
|
if ($oNode->tagName != 'class')
|
|
|
{
|
|
|
$this->_priv_SetFlag($oNode->parentNode, 'modified');
|
|
@@ -865,7 +1113,21 @@ class ModelFactory
|
|
|
$iDepth++;
|
|
|
foreach($oNode->childNodes as $oChildNode)
|
|
|
{
|
|
|
- $sOperation = $oChildNode->getAttribute('_operation');
|
|
|
+ $sNodeName = $oChildNode->nodeName;
|
|
|
+ $sNodeValue = $oChildNode->nodeValue;
|
|
|
+ if (!$oChildNode instanceof DOMElement)
|
|
|
+ {
|
|
|
+ $sName = '$$';
|
|
|
+ $sOperation = $oChildNode->parentNode->getAttribute('_operation');
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $sName = $oChildNode->getAttribute('name');;
|
|
|
+ $sOperation = $oChildNode->getAttribute('_operation');
|
|
|
+ }
|
|
|
+
|
|
|
+//echo str_repeat('+', $iDepth)." $sNodeName [$sName], operation: $sOperation\n";
|
|
|
+
|
|
|
switch($sOperation)
|
|
|
{
|
|
|
case 'removed':
|
|
@@ -883,19 +1145,60 @@ class ModelFactory
|
|
|
//echo "<p>".str_repeat('+', $iDepth).$oChildNode->getAttribute('name')." was removed...</p>";
|
|
|
break;
|
|
|
|
|
|
+ case 'added':
|
|
|
+//echo "<p>".str_repeat('+', $iDepth).$oChildNode->tagName.':'.$oChildNode->getAttribute('name')." was created...</p>";
|
|
|
+ $oModifiedNode = $oDoc->importNode($oChildNode, true); // Copies all the node's attributes, and the child nodes as well
|
|
|
+ if ($oChildNode instanceof DOMElement)
|
|
|
+ {
|
|
|
+ $oModifiedNode->removeAttribute('_source');
|
|
|
+ if ($oModifiedNode->tagName == 'class')
|
|
|
+ {
|
|
|
+ // classes are always located under the root node
|
|
|
+ $oDoc->firstChild->appendChild($oModifiedNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oDestNode->appendChild($oModifiedNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oDestNode->appendChild($oModifiedNode);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'replaced':
|
|
|
+//echo "<p>".str_repeat('+', $iDepth).$oChildNode->tagName.':'.$oChildNode->getAttribute('name')." was replaced...</p>";
|
|
|
+ $oModifiedNode = $oDoc->importNode($oChildNode, true); // Copies all the node's attributes, and the child nodes as well
|
|
|
+ if ($oChildNode instanceof DOMElement)
|
|
|
+ {
|
|
|
+ $oModifiedNode->removeAttribute('_source');
|
|
|
+ }
|
|
|
+ $oDestNode->appendChild($oModifiedNode);
|
|
|
+ break;
|
|
|
+
|
|
|
case 'modified':
|
|
|
- case 'created':
|
|
|
- //echo "<p>".str_repeat('+', $iDepth).$oChildNode->tagName.':'.$oChildNode->getAttribute('name')." was modified...</p>";
|
|
|
- $oModifiedNode = $oDoc->importNode($oChildNode->cloneNode(false)); // Copies all the node's attributes, but NOT the child nodes
|
|
|
- $oModifiedNode->removeAttribute('_source');
|
|
|
- $this->_priv_ImportModifiedChildren($oDoc, $oModifiedNode, $oChildNode);
|
|
|
- if ($oModifiedNode->tagName == 'class')
|
|
|
+//echo "<p>".str_repeat('+', $iDepth).$oChildNode->tagName.':'.$oChildNode->getAttribute('name')." was modified...</p>";
|
|
|
+ if ($oChildNode instanceof DOMElement)
|
|
|
{
|
|
|
- // classes are always located under the root node
|
|
|
- $oDoc->firstChild->appendChild($oModifiedNode);
|
|
|
+//echo str_repeat('+', $iDepth)." Copying (NON recursively) the modified node\n";
|
|
|
+ $oModifiedNode = $oDoc->importNode($oChildNode, false); // Copies all the node's attributes, but NOT the child nodes
|
|
|
+ $oModifiedNode->removeAttribute('_source');
|
|
|
+ $this->_priv_ImportModifiedChildren($oDoc, $oModifiedNode, $oChildNode);
|
|
|
+ if ($oModifiedNode->tagName == 'class')
|
|
|
+ {
|
|
|
+ // classes are always located under the root node
|
|
|
+ $oDoc->firstChild->appendChild($oModifiedNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oDestNode->appendChild($oModifiedNode);
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
+//echo str_repeat('+', $iDepth)." Copying (recursively) the modified node\n";
|
|
|
+ $oModifiedNode = $oDoc->importNode($oChildNode, true); // Copies all the node's attributes, and the child nodes
|
|
|
$oDestNode->appendChild($oModifiedNode);
|
|
|
}
|
|
|
break;
|
|
@@ -903,14 +1206,18 @@ class ModelFactory
|
|
|
default:
|
|
|
// No change: search if there is not a modified child class
|
|
|
$oModifiedNode = $oDoc->importNode($oChildNode->cloneNode(false)); // Copies all the node's attributes, but NOT the child nodes
|
|
|
- $oModifiedNode->removeAttribute('_source');
|
|
|
- if ($oChildNode->tagName == 'class')
|
|
|
+//echo str_repeat('+', $iDepth)." Importing (NON recursively) the modified node\n";
|
|
|
+ if ($oChildNode instanceof DOMElement)
|
|
|
{
|
|
|
-//echo "<p>".str_repeat('+', $iDepth)."Checking if a subclass of ".$oChildNode->getAttribute('name')." was modified...</p>";
|
|
|
- // classes are always located under the root node
|
|
|
- $this->_priv_ImportModifiedChildren($oDoc, $oModifiedNode, $oChildNode);
|
|
|
+ $oModifiedNode->removeAttribute('_source');
|
|
|
}
|
|
|
}
|
|
|
+ if ($oChildNode->tagName == 'class')
|
|
|
+ {
|
|
|
+//echo "<p>".str_repeat('+', $iDepth)."Checking if a subclass of ".$oChildNode->getAttribute('name')." was modified...</p>";
|
|
|
+ // classes are always located under the root node
|
|
|
+ $this->_priv_ImportModifiedChildren($oDoc, $oModifiedNode, $oChildNode);
|
|
|
+ }
|
|
|
}
|
|
|
$iDepth--;
|
|
|
}
|
|
@@ -986,4 +1293,91 @@ class ModelFactory
|
|
|
public function _priv_SetNodeAttribute(DOMNode $oNode, $sAttributeName, $atttribueValue)
|
|
|
{
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Helper to browse the DOM -could be factorized in ModelFactory
|
|
|
+ * Returns the node directly under the given node, and that is supposed to be always present and unique
|
|
|
+ */
|
|
|
+ protected function GetUniqueElement($oDOMNode, $sTagName, $bMustExist = true)
|
|
|
+ {
|
|
|
+ $oNode = null;
|
|
|
+ foreach($oDOMNode->childNodes as $oChildNode)
|
|
|
+ {
|
|
|
+ if ($oChildNode->nodeName == $sTagName)
|
|
|
+ {
|
|
|
+ $oNode = $oChildNode;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($bMustExist && is_null($oNode))
|
|
|
+ {
|
|
|
+ throw new DOMFormatException('Missing unique tag: '.$sTagName);
|
|
|
+ }
|
|
|
+ return $oNode;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Helper to browse the DOM -could be factorized in ModelFactory
|
|
|
+ * Returns the node directly under the given node, or null is missing
|
|
|
+ */
|
|
|
+ protected function GetOptionalElement($oDOMNode, $sTagName)
|
|
|
+ {
|
|
|
+ return $this->GetUniqueElement($oDOMNode, $sTagName, false);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Helper to browse the DOM -could be factorized in ModelFactory
|
|
|
+ * Returns the TEXT of the given node (possibly from several subnodes)
|
|
|
+ */
|
|
|
+ protected function GetNodeText($oNode)
|
|
|
+ {
|
|
|
+ $sText = '';
|
|
|
+ foreach($oNode->childNodes as $oChildNode)
|
|
|
+ {
|
|
|
+ if ($oChildNode instanceof DOMCharacterData) // Base class of DOMText and DOMCdataSection
|
|
|
+ {
|
|
|
+ $sText .= $oChildNode->wholeText;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $sText;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Helper to browse the DOM -could be factorized in ModelFactory
|
|
|
+ * Assumes the given node to be either a text or
|
|
|
+ * <items>
|
|
|
+ * <item [key]="..."]>value<item>
|
|
|
+ * <item [key]="..."]>value<item>
|
|
|
+ * </items>
|
|
|
+ * where value can be the either a text or an array of items... recursively
|
|
|
+ * Returns a PHP array
|
|
|
+ */
|
|
|
+ public function GetNodeAsArrayOfItems($oNode)
|
|
|
+ {
|
|
|
+ $oItems = $this->GetOptionalElement($oNode, 'items');
|
|
|
+ if ($oItems)
|
|
|
+ {
|
|
|
+ $res = array();
|
|
|
+ foreach($oItems->childNodes as $oItem)
|
|
|
+ {
|
|
|
+ // When an attribute is missing
|
|
|
+ if ($oItem->hasAttribute('key'))
|
|
|
+ {
|
|
|
+ $key = $oItem->getAttribute('key');
|
|
|
+ $res[$key] = $this->GetNodeAsArrayOfItems($oItem);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $res[] = $this->GetNodeAsArrayOfItems($oItem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $res = $this->GetNodeText($oNode);
|
|
|
+ }
|
|
|
+ return $res;
|
|
|
+ }
|
|
|
+
|
|
|
}
|