/**
  * Helper to check wether the table has been created into the DB 
  * (this table did not exist in 1.0.1 and older versions)
  */
 public static function IsInstalled()
 {
     $sTable = MetaModel::DBGetTable(__CLASS__);
     if (CMDBSource::IsTable($sTable)) {
         return true;
     } else {
         return false;
     }
     return false;
 }
예제 #2
0
 /**
  * Handler called after the creation/update of the database schema
  * @param $oConfiguration Config The new configuration of the application
  * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
  * @param $sCurrentVersion string Current version number of the module
  */
 public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
 {
     // For each record having item_org_id unset,
     //    get the org_id from the container object
     //
     // Prerequisite: change null into 0 (workaround to the fact that we cannot use IS NULL in OQL)
     SetupPage::log_info("Initializing attachment/item_org_id - null to zero");
     $sTableName = MetaModel::DBGetTable('Attachment');
     $sRepair = "UPDATE `{$sTableName}` SET `item_org_id` = 0 WHERE `item_org_id` IS NULL";
     CMDBSource::Query($sRepair);
     SetupPage::log_info("Initializing attachment/item_org_id - zero to the container");
     $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_org_id = 0");
     $oSet = new DBObjectSet($oSearch);
     $iUpdated = 0;
     while ($oAttachment = $oSet->Fetch()) {
         $oContainer = MetaModel::GetObject($oAttachment->Get('item_class'), $oAttachment->Get('item_id'), false, true);
         if ($oContainer) {
             $oAttachment->SetItem($oContainer, true);
             $iUpdated++;
         }
     }
     SetupPage::log_info("Initializing attachment/item_org_id - {$iUpdated} records have been adjusted");
 }
 /**
  * Helper to modify an enum value	
  * The change is made in the datamodel definition, but the value has to be changed in the DB as well	 	 
  * Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation()
  * This helper does change ONE value at a time	 
  * 	 
  * @param string $sClass A valid class name
  * @param string $sAttCode The enum attribute code
  * @param string $sFrom Original value (already INVALID in the current datamodel)	 	
  * @param string $sTo New value (valid in the current datamodel)
  * @return void	 	 	
  */
 public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo)
 {
     try {
         $sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
         $sTableName = MetaModel::DBGetTable($sOriginClass);
         $oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode);
         if ($oAttDef instanceof AttributeEnum) {
             $oValDef = $oAttDef->GetValuesDef();
             if ($oValDef) {
                 $aNewValues = array_keys($oValDef->GetValues(array(), ""));
                 if (in_array($sTo, $aNewValues)) {
                     $sEnumCol = $oAttDef->Get("sql");
                     $aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `{$sTableName}` WHERE Field = '{$sEnumCol}'");
                     if (isset($aFields[0]['Type'])) {
                         $sColType = $aFields[0]['Type'];
                         // Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string
                         if (preg_match("/^enum\\(\\'(.*)\\'\\)\$/", $sColType, $aMatches)) {
                             $aCurrentValues = explode("','", $aMatches[1]);
                         }
                     }
                     if (!in_array($sFrom, $aNewValues)) {
                         if (!in_array($sTo, $aCurrentValues)) {
                             $sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL';
                             if (strtolower($sTo) == strtolower($sFrom)) {
                                 SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}' (just a change in the case)");
                                 $aTargetValues = array();
                                 foreach ($aCurrentValues as $sValue) {
                                     if ($sValue == $sFrom) {
                                         $sValue = $sTo;
                                     }
                                     $aTargetValues[] = $sValue;
                                 }
                                 $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}";
                                 $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                                 CMDBSource::Query($sRepair);
                             } else {
                                 // 1st - Allow both values in the column definition
                                 //
                                 SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}'");
                                 $aAllValues = $aCurrentValues;
                                 $aAllValues[] = $sTo;
                                 $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aAllValues)) . ") {$sNullSpec}";
                                 $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                                 CMDBSource::Query($sRepair);
                                 // 2nd - Change the old value into the new value
                                 //
                                 $sRepair = "UPDATE `{$sTableName}` SET `{$sEnumCol}` = '{$sTo}' WHERE `{$sEnumCol}` = BINARY '{$sFrom}'";
                                 CMDBSource::Query($sRepair);
                                 $iAffectedRows = CMDBSource::AffectedRows();
                                 SetupPage::log_info("Changing enum in DB - {$iAffectedRows} rows updated");
                                 // 3rd - Remove the useless value from the column definition
                                 //
                                 $aTargetValues = array();
                                 foreach ($aCurrentValues as $sValue) {
                                     if ($sValue == $sFrom) {
                                         $sValue = $sTo;
                                     }
                                     $aTargetValues[] = $sValue;
                                 }
                                 $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}";
                                 $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                                 CMDBSource::Query($sRepair);
                                 SetupPage::log_info("Changing enum in DB - removed useless value '{$sFrom}'");
                             }
                         }
                     } else {
                         SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sFrom}' is still a valid value (" . implode(', ', $aNewValues) . ")");
                     }
                 } else {
                     SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' is not a known value (" . implode(', ', $aNewValues) . ")");
                 }
             }
         }
     } catch (Exception $e) {
         SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' failed. Reason " . $e->getMessage());
     }
 }
 /**
  * Gets the definitions of the 3 triggers: before insert, before update and after delete
  * @return array An array with 3 entries, one for each of the SQL queries
  */
 protected function GetTriggersDefinition()
 {
     $sTable = $this->GetDataTable();
     $sReplicaTable = MetaModel::DBGetTable('SynchroReplica');
     $aColumns = $this->GetSQLColumns();
     $aResult = array();
     $sTriggerInsert = "CREATE TRIGGER `{$sTable}_bi` BEFORE INSERT ON `{$sTable}`";
     $sTriggerInsert .= "   FOR EACH ROW";
     $sTriggerInsert .= "   BEGIN";
     $sTriggerInsert .= "      INSERT INTO `{$sReplicaTable}` (`sync_source_id`, `status_last_seen`, `status`) VALUES ({$this->GetKey()}, NOW(), 'new');";
     $sTriggerInsert .= "      SET NEW.id = LAST_INSERT_ID();";
     $sTriggerInsert .= "   END;";
     $aResult['bi'] = $sTriggerInsert;
     $aModified = array();
     foreach ($aColumns as $sColumn => $ColSpec) {
         // <=> is a null-safe 'EQUALS' operator (there is no equivalent for "DIFFERS FROM")
         $aModified[] = "NOT(NEW.`{$sColumn}` <=> OLD.`{$sColumn}`)";
     }
     $sIsModified = '(' . implode(') OR (', $aModified) . ')';
     // Update the replica
     //
     // status is forced to "new" if the replica was obsoleted directly from the state "new" (dest_id = null)
     // otherwise, if status was either 'obsolete' or 'synchronized' it is turned into 'modified' or 'synchronized' depending on the changes
     // otherwise, the status is left as is
     $sTriggerUpdate = "CREATE TRIGGER `{$sTable}_bu` BEFORE UPDATE ON `{$sTable}`";
     $sTriggerUpdate .= "   FOR EACH ROW";
     $sTriggerUpdate .= "   BEGIN";
     $sTriggerUpdate .= "      IF @itopuser is null THEN";
     $sTriggerUpdate .= "         UPDATE `{$sReplicaTable}` SET status_last_seen = NOW(), `status` = IF(`status` = 'obsolete', IF(`dest_id` IS NULL, 'new', 'modified'), IF(`status` IN ('synchronized') AND ({$sIsModified}), 'modified', `status`)) WHERE sync_source_id = {$this->GetKey()} AND id = OLD.id;";
     $sTriggerUpdate .= "         SET NEW.id = OLD.id;";
     // make sure this id won't change
     $sTriggerUpdate .= "      END IF;";
     $sTriggerUpdate .= "   END;";
     $aResult['bu'] = $sTriggerUpdate;
     $sTriggerDelete = "CREATE TRIGGER `{$sTable}_ad` AFTER DELETE ON `{$sTable}`";
     $sTriggerDelete .= "   FOR EACH ROW";
     $sTriggerDelete .= "   BEGIN";
     $sTriggerDelete .= "      DELETE FROM `{$sReplicaTable}` WHERE id = OLD.id;";
     $sTriggerDelete .= "   END;";
     $aResult['ad'] = $sTriggerDelete;
     return $aResult;
 }
 protected function MakeSQLObjectQuerySingleTable(&$oBuild, $aAttToLoad, $sTableClass, $aExtKeys, $aValues)
 {
     // $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields))
     //echo "MakeSQLObjectQuery($sTableClass)-liste des clefs externes($sTableClass): <pre>".print_r($aExtKeys, true)."</pre><br/>\n";
     // Prepare the query for a single table (compound objects)
     // Ignores the items (attributes/filters) that are not on the target table
     // Perform an (inner or left) join for every external key (and specify the expected fields)
     //
     // Returns an SQLQuery
     //
     $sTargetClass = $this->GetFirstJoinedClass();
     $sTargetAlias = $this->GetFirstJoinedClassAlias();
     $sTable = MetaModel::DBGetTable($sTableClass);
     $sTableAlias = $oBuild->GenerateTableAlias($sTargetAlias . '_' . $sTable, $sTable);
     $aTranslation = array();
     $aExpectedAtts = array();
     $oBuild->m_oQBExpressions->GetUnresolvedFields($sTargetAlias, $aExpectedAtts);
     $bIsOnQueriedClass = array_key_exists($sTargetAlias, $oBuild->GetRootFilter()->GetSelectedClasses());
     self::DbgTrace("Entering: tableclass={$sTableClass}, filter=" . $this->ToOQL() . ", " . ($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
     // 1 - SELECT and UPDATE
     //
     // Note: no need for any values nor fields for foreign Classes (ie not the queried Class)
     //
     $aUpdateValues = array();
     // 1/a - Get the key and friendly name
     //
     // We need one pkey to be the key, let's take the first one available
     $oSelectedIdField = null;
     $oIdField = new FieldExpressionResolved(MetaModel::DBGetKey($sTableClass), $sTableAlias);
     $aTranslation[$sTargetAlias]['id'] = $oIdField;
     if ($bIsOnQueriedClass) {
         // Add this field to the list of queried fields (required for the COUNT to work fine)
         $oSelectedIdField = $oIdField;
     }
     // 1/b - Get the other attributes
     //
     foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) {
         // Skip this attribute if not defined in this table
         if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) {
             continue;
         }
         // Skip this attribute if not made of SQL columns
         if (count($oAttDef->GetSQLExpressions()) == 0) {
             continue;
         }
         // Update...
         //
         if ($bIsOnQueriedClass && array_key_exists($sAttCode, $aValues)) {
             assert($oAttDef->IsDirectField());
             foreach ($oAttDef->GetSQLValues($aValues[$sAttCode]) as $sColumn => $sValue) {
                 $aUpdateValues[$sColumn] = $sValue;
             }
         }
     }
     // 2 - The SQL query, for this table only
     //
     $oSelectBase = new SQLObjectQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField);
     // 3 - Resolve expected expressions (translation table: alias.attcode => table.column)
     //
     foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) {
         // Skip this attribute if not defined in this table
         if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) {
             continue;
         }
         // Select...
         //
         if ($oAttDef->IsExternalField()) {
             // skip, this will be handled in the joined tables (done hereabove)
         } else {
             //echo "<p>MakeSQLObjectQuerySingleTable: Field $sAttCode is part of the table $sTable (named: $sTableAlias)</p>";
             // standard field, or external key
             // add it to the output
             foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) {
                 if (array_key_exists($sAttCode . $sColId, $aExpectedAtts)) {
                     $oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
                     foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) {
                         $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sTargetClass, $sAttCode, $sColId, $oFieldSQLExp, $oSelectBase);
                     }
                     $aTranslation[$sTargetAlias][$sAttCode . $sColId] = $oFieldSQLExp;
                 }
             }
         }
     }
     //echo "MakeSQLObjectQuery- Classe $sTableClass<br/>\n";
     // 4 - The external keys -> joins...
     //
     $aAllPointingTo = $this->GetCriteria_PointingTo();
     if (array_key_exists($sTableClass, $aExtKeys)) {
         foreach ($aExtKeys[$sTableClass] as $sKeyAttCode => $aExtFields) {
             $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode);
             $aPointingTo = $this->GetCriteria_PointingTo($sKeyAttCode);
             //echo "MakeSQLObjectQuery-Cle '$sKeyAttCode'<br/>\n";
             if (!array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo)) {
                 //echo "MakeSQLObjectQuery-Ajoutons l'operateur TREE_OPERATOR_EQUALS pour $sKeyAttCode<br/>\n";
                 // The join was not explicitely defined in the filter,
                 // we need to do it now
                 $sKeyClass = $oKeyAttDef->GetTargetClass();
                 $sKeyClassAlias = $oBuild->GenerateClassAlias($sKeyClass . '_' . $sKeyAttCode, $sKeyClass);
                 $oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias);
                 $aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter;
             }
         }
     }
     //echo "MakeSQLObjectQuery-liste des clefs de jointure: <pre>".print_r(array_keys($aAllPointingTo), true)."</pre><br/>\n";
     foreach ($aAllPointingTo as $sKeyAttCode => $aPointingTo) {
         foreach ($aPointingTo as $iOperatorCode => $aFilter) {
             foreach ($aFilter as $oExtFilter) {
                 if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) {
                     continue;
                 }
                 // Not defined in the class, skip it
                 // The aliases should not conflict because normalization occured while building the filter
                 $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode);
                 $sKeyClass = $oExtFilter->GetFirstJoinedClass();
                 $sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias();
                 //echo "MakeSQLObjectQuery-$sTableClass::$sKeyAttCode Foreach PointingTo($iOperatorCode) <span style=\"color:red\">$sKeyClass (alias:$sKeyClassAlias)</span><br/>\n";
                 // Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree
                 //echo "MakeSQLObjectQuery-array_key_exists($sTableClass, \$aExtKeys)<br/>\n";
                 if ($iOperatorCode == TREE_OPERATOR_EQUALS) {
                     if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass])) {
                         // Specify expected attributes for the target class query
                         // ... and use the current alias !
                         $aTranslateNow = array();
                         // Translation for external fields - must be performed before the join is done (recursion...)
                         foreach ($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt) {
                             //echo "MakeSQLObjectQuery aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n";
                             if ($oAtt instanceof AttributeFriendlyName) {
                                 // Note: for a given ext key, there is one single attribute "friendly name"
                                 $aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
                                 //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);</b></p>\n";
                             } else {
                                 $sExtAttCode = $oAtt->GetExtAttCode();
                                 // Translate mainclass.extfield => remoteclassalias.remotefieldcode
                                 $oRemoteAttDef = MetaModel::GetAttributeDef($sKeyClass, $sExtAttCode);
                                 foreach ($oRemoteAttDef->GetSQLExpressions() as $sColId => $sRemoteAttExpr) {
                                     $aTranslateNow[$sTargetAlias][$sAttCode . $sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
                                     //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n";
                                 }
                                 //echo "<p><b>ExtAttr2: $sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</b></p>\n";
                             }
                         }
                         if ($oKeyAttDef instanceof AttributeObjectKey) {
                             // Add the condition: `$sTargetAlias`.$sClassAttCode IN (subclasses of $sKeyClass')
                             $sClassAttCode = $oKeyAttDef->Get('class_attcode');
                             $oClassAttDef = MetaModel::GetAttributeDef($sTargetClass, $sClassAttCode);
                             foreach ($oClassAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) {
                                 $aTranslateNow[$sTargetAlias][$sClassAttCode . $sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
                             }
                             $oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sKeyClass, ENUM_CHILD_CLASSES_ALL));
                             $oClassExpr = new FieldExpression($sClassAttCode, $sTargetAlias);
                             $oClassRestriction = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
                             $oBuild->m_oQBExpressions->AddCondition($oClassRestriction);
                         }
                         // Translate prior to recursing
                         //
                         //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n";
                         $oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
                         //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
                         //echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeSQLObjectQuery()/p>\n";
                         self::DbgTrace("External key {$sKeyAttCode} (class: {$sKeyClass}), call MakeSQLObjectQuery()");
                         $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
                         //echo "<p>Recursive MakeSQLObjectQuery ".__LINE__.": <pre>\n".print_r($oBuild->GetRootFilter()->GetSelectedClasses(), true)."</pre></p>\n";
                         $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad);
                         $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
                         $sExternalKeyTable = $oJoinExpr->GetParent();
                         $sExternalKeyField = $oJoinExpr->GetName();
                         $aCols = $oKeyAttDef->GetSQLExpressions();
                         // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
                         $sLocalKeyField = current($aCols);
                         // get the first column for an external key
                         self::DbgTrace("External key {$sKeyAttCode}, Join on {$sLocalKeyField} = {$sExternalKeyField}");
                         if ($oKeyAttDef->IsNullAllowed()) {
                             $oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
                         } else {
                             $oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
                         }
                     }
                 } elseif (MetaModel::GetAttributeOrigin($sKeyClass, $sKeyAttCode) == $sTableClass) {
                     $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
                     $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad);
                     $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
                     $sExternalKeyTable = $oJoinExpr->GetParent();
                     $sExternalKeyField = $oJoinExpr->GetName();
                     $sLeftIndex = $sExternalKeyField . '_left';
                     // TODO use GetSQLLeft()
                     $sRightIndex = $sExternalKeyField . '_right';
                     // TODO use GetSQLRight()
                     $LocalKeyLeft = $oKeyAttDef->GetSQLLeft();
                     $LocalKeyRight = $oKeyAttDef->GetSQLRight();
                     $oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $LocalKeyRight, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode);
                 }
             }
         }
     }
     // Translate the selected columns
     //
     //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
     $oBuild->m_oQBExpressions->Translate($aTranslation, false);
     //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
     //MyHelpers::var_dump_html($oSelectBase->RenderSelect());
     return $oSelectBase;
 }
예제 #6
0
 protected function DBDeleteSingleObject()
 {
     if (!MetaModel::DBIsReadOnly()) {
         $this->OnDelete();
         $this->RecordObjDeletion($this->m_iKey);
         // May cause a reload for storing history information
         foreach (MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef) {
             if ($oAttDef->IsHierarchicalKey()) {
                 // Update the left & right indexes for each hierarchical key
                 $sTable = $sTable = MetaModel::DBGetTable(get_class($this), $sAttCode);
                 $sSQL = "SELECT `" . $oAttDef->GetSQLRight() . "` AS `right`, `" . $oAttDef->GetSQLLeft() . "` AS `left` FROM `{$sTable}` WHERE id=" . CMDBSource::Quote($this->m_iKey);
                 $aRes = CMDBSource::QueryToArray($sSQL);
                 $iMyLeft = $aRes[0]['left'];
                 $iMyRight = $aRes[0]['right'];
                 $iDelta = $iMyRight - $iMyLeft + 1;
                 MetaModel::HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable);
                 // No new parent for now, insert completely at the right of the tree
                 $sSQL = "SELECT max(`" . $oAttDef->GetSQLRight() . "`) AS max FROM `{$sTable}`";
                 $aRes = CMDBSource::QueryToArray($sSQL);
                 if (count($aRes) == 0) {
                     $iNewLeft = 1;
                 } else {
                     $iNewLeft = $aRes[0]['max'] + 1;
                 }
                 MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
             }
         }
         foreach (MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL) as $sParentClass) {
             $this->DBDeleteSingleTable($sParentClass);
         }
         $this->AfterDelete();
         $this->m_bIsInDB = false;
         // Fix for #926: do NOT reset m_iKey as it can be used to have it for reporting purposes (see the REST service to delete objects, reported as bug #926)
         // Thought the key is not reset, using DBInsert or DBWrite will create an object having the same characteristics and a new ID. DBUpdate is protected
     }
 }
예제 #7
0
 /**
  * Helper to remove selected objects without calling any handler
  * Surpasses BulkDelete as it can handle abstract classes, but has the other limitation as it bypasses standard objects handlers 
  * 	 
  * @param string $oFilter Scope of objects to wipe out
  * @return The count of deleted objects
  */
 public static function PurgeData($oFilter)
 {
     $sTargetClass = $oFilter->GetClass();
     $oSet = new DBObjectSet($oFilter);
     $oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
     $aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
     $aIds = array_keys($aIdToClass);
     if (count($aIds) > 0) {
         $aQuotedIds = CMDBSource::Quote($aIds);
         $sIdList = implode(',', $aQuotedIds);
         $aTargetClasses = array_merge(self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL), self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF));
         foreach ($aTargetClasses as $sSomeClass) {
             $sTable = MetaModel::DBGetTable($sSomeClass);
             $sPKField = MetaModel::DBGetKey($sSomeClass);
             $sDeleteSQL = "DELETE FROM `{$sTable}` WHERE `{$sPKField}` IN ({$sIdList})";
             CMDBSource::DeleteFrom($sDeleteSQL);
         }
     }
     return count($aIds);
 }
 /**
  * Helper to modify an enum value	
  * The change is made in the datamodel definition, but the value has to be changed in the DB as well	 	 
  * Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation()
  * 	 
  * @param string $sClass A valid class name
  * @param string $sAttCode The enum attribute code
  * @param string $sFrom Original value (already INVALID in the current datamodel)	 	
  * @param string $sTo New value (valid in the current datamodel)
  * @return void	 	 	
  */
 public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo)
 {
     $sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
     $sTableName = MetaModel::DBGetTable($sOriginClass);
     $oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode);
     if ($oAttDef instanceof AttributeEnum) {
         $oValDef = $oAttDef->GetValuesDef();
         if ($oValDef) {
             $aNewValues = array_keys($oValDef->GetValues(array(), ""));
             if (in_array($sTo, $aNewValues)) {
                 $aAllValues = $aNewValues;
                 $aAllValues[] = $sFrom;
                 if (!in_array($sFrom, $aNewValues)) {
                     $sEnumCol = $oAttDef->Get("sql");
                     $sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL';
                     if (strtolower($sTo) == strtolower($sFrom)) {
                         SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}' (just a change in the case)");
                         $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aNewValues)) . ") {$sNullSpec}";
                         $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                         CMDBSource::Query($sRepair);
                     } else {
                         // 1st - Allow both values in the column definition
                         //
                         SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}'");
                         $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aAllValues)) . ") {$sNullSpec}";
                         $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                         CMDBSource::Query($sRepair);
                         // 2nd - Change the old value into the new value
                         //
                         $sRepair = "UPDATE `{$sTableName}` SET `{$sEnumCol}` = '{$sTo}' WHERE `{$sEnumCol}` = BINARY '{$sFrom}'";
                         CMDBSource::Query($sRepair);
                         $iAffectedRows = CMDBSource::AffectedRows();
                         SetupPage::log_info("Changing enum in DB - {$iAffectedRows} rows updated");
                         // 3rd - Remove the useless value from the column definition
                         //
                         $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aNewValues)) . ") {$sNullSpec}";
                         $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}";
                         CMDBSource::Query($sRepair);
                         SetupPage::log_info("Changing enum in DB - removed useless value '{$sFrom}'");
                     }
                 } else {
                     SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sFrom}' is still a valid value (" . implode(', ', $aNewValues) . ")");
                 }
             } else {
                 SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' is not a known value (" . implode(', ', $aNewValues) . ")");
             }
         }
     }
 }