private function DBDeleteSingleTable($sTableClass) { $sTable = MetaModel::DBGetTable($sTableClass); // Abstract classes or classes having no specific attribute do not have an associated table if ($sTable == '') { return; } $sPKField = '`' . MetaModel::DBGetKey($sTableClass) . '`'; $sKey = CMDBSource::Quote($this->m_iKey); $sDeleteSQL = "DELETE FROM `{$sTable}` WHERE {$sPKField} = {$sKey}"; CMDBSource::DeleteFrom($sDeleteSQL); }
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; }
/** * 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); }