diff --git a/application/applicationcontext.class.inc.php b/application/applicationcontext.class.inc.php index 374b6ceb0..0d5f27f4d 100644 --- a/application/applicationcontext.class.inc.php +++ b/application/applicationcontext.class.inc.php @@ -303,5 +303,58 @@ class ApplicationContext return ''; } } + + protected static $m_aPluginProperties = null; + + /** + * Load plugin properties for the current session + * @return void + */ + protected static function LoadPluginProperties() + { + if (isset($_SESSION['PluginProperties'])) + { + self::$m_aPluginProperties = $_SESSION['PluginProperties']; + } + else + { + self::$m_aPluginProperties = array(); + } + } + + /** + * Set plugin properties + * @param sPluginClass string Class implementing any plugin interface + * @param sProperty string Name of the property + * @param value scalar Value (numeric or string) + * @return void + */ + public static function SetPluginProperty($sPluginClass, $sProperty, $value) + { + if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); + + self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value; + $_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value; + } + + /** + * Get plugin properties + * @param sPluginClass string Class implementing any plugin interface + * @return array of sProperty=>value pairs + */ + public static function GetPluginProperties($sPluginClass) + { + if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); + + if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) + { + return self::$m_aPluginProperties[$sPluginClass]; + } + else + { + return array(); + } + } + } ?> diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php index a31b8ede9..5c0aa9051 100644 --- a/core/cmdbobject.class.inc.php +++ b/core/cmdbobject.class.inc.php @@ -93,6 +93,23 @@ abstract class CMDBObject extends DBObject protected static $m_oCurrChange = null; + public static function SetCurrentChange(CMDBChange $oChange) + { + self::$m_oCurrChange = $oChange; + } + + // + // Todo: simplify the APIs and do not pass the current change as an argument anymore + // SetCurrentChange to be invoked in very few cases (UI.php, CSV import, Data synchro) + // GetCurrentChange to be called ONCE (!) by CMDBChangeOp::OnInsert ($this->Set('change', ..GetCurrentChange()) + // GetCurrentChange to create a default change if not already done in the current context + // + public static function GetCurrentChange() + { + return self::$m_oCurrChange; + } + + private function RecordObjCreation(CMDBChange $oChange) { $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate"); diff --git a/core/dbobject.class.php b/core/dbobject.class.php index a87796a94..cc99af76b 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1302,6 +1302,11 @@ abstract class DBObject return $this->DBInsert(); } + public function DBInsertTrackedNoReload(CMDBChange $oVoid) + { + return $this->DBInsertNoReload(); + } + // Creates a copy of the current object into the database // Returns the id of the newly created object public function DBClone($iNewKey = null) diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index 0d6c54247..a8add04e2 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -66,6 +66,8 @@ class DBObjectSearch $this->m_aRelatedTo = array(); $this->m_bDataFiltered = false; $this->m_aParentConditions = array(); + + $this->m_aModifierProperties = array(); } public function AllowAllData() {$this->m_bAllowAllData = true;} @@ -126,6 +128,23 @@ class DBObjectSearch } + public function SetModifierProperty($sPluginClass, $sProperty, $value) + { + $this->m_aModifierProperties[$sPluginClass][$sProperty] = $value; + } + + public function GetModifierProperties($sPluginClass) + { + if (array_key_exists($sPluginClass, $this->m_aModifierProperties)) + { + return $this->m_aModifierProperties[$sPluginClass]; + } + else + { + return array(); + } + } + public function IsAny() { // #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false; diff --git a/core/expression.class.inc.php b/core/expression.class.inc.php index ad2590ca9..75f6184fa 100644 --- a/core/expression.class.inc.php +++ b/core/expression.class.inc.php @@ -953,10 +953,10 @@ class QueryBuilderExpressions protected $m_aSelectExpr; protected $m_aJoinFields; - public function __construct($aSelect, $oCondition) + public function __construct($oCondition) { $this->m_oConditionExpr = $oCondition; - $this->m_aSelectExpr = $aSelect; + $this->m_aSelectExpr = array(); $this->m_aJoinFields = array(); } diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 6b7c97bf1..f66eb8b40 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -15,6 +15,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require_once(APPROOT.'core/modulehandler.class.inc.php'); +require_once(APPROOT.'core/querybuildercontext.class.inc.php'); +require_once(APPROOT.'core/querymodifier.class.inc.php'); /** * Metamodel @@ -25,8 +27,6 @@ require_once(APPROOT.'core/modulehandler.class.inc.php'); * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ - - // #@# todo: change into class const (see Doctrine) // Doctrine example // class toto @@ -1404,7 +1404,7 @@ abstract class MetaModel // Build the list of available extensions // - $aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension'); + $aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier'); foreach($aInterfaces as $sInterface) { self::$m_aExtensionClasses[$sInterface] = array(); @@ -1924,12 +1924,26 @@ abstract class MetaModel } } + // Compute query modifiers properties (can be set in the search itself, by the context, etc.) + // + $aModifierProperties = self::MakeModifierProperties($oFilter); + if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries) { // Need to identify the query $sOqlQuery = $oFilter->ToOql(); - $sRawId = $sOqlQuery; + if (count($aModifierProperties)) + { + array_multisort($aModifierProperties); + $sModifierProperties = json_encode($aModifierProperties); + } + else + { + $sModifierProperties = ''; + } + + $sRawId = $sOqlQuery.$sModifierProperties; if (!is_null($aAttToLoad)) { foreach($aAttToLoad as $sAlias => $aAttributes) @@ -2024,12 +2038,10 @@ abstract class MetaModel if (!isset($oSelect)) { - $aClassAliases = array(); - $aTableAliases = array(); - $oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria()); + $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties); $oKPI = new ExecutionKPI(); - $oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $aAttToLoad, array(), true /* main query */); + $oSelect = self::MakeQuery($oBuild, $oFilter, $aAttToLoad, array(), true /* main query */); $oSelect->SetSourceOQL($sOqlQuery); $oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery); @@ -2138,12 +2150,33 @@ abstract class MetaModel } } + protected static function MakeModifierProperties($oFilter) + { + // Compute query modifiers properties (can be set in the search itself, by the context, etc.) + // + $aModifierProperties = array(); + foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) + { + // Lowest precedence: the application context + $aPluginProps = ApplicationContext::GetPluginProperties($sPluginClass); + // Highest precedence: programmatically specified (or OQL) + foreach($oFilter->GetModifierProperties($sPluginClass) as $sProp => $value) + { + $aPluginProps[$sProp] = $value; + } + if (count($aPluginProps) > 0) + { + $aModifierProperties[$sPluginClass] = $aPluginProps; + } + } + return $aModifierProperties; + } + public static function MakeDeleteQuery(DBObjectSearch $oFilter, $aArgs = array()) { - $aClassAliases = array(); - $aTableAliases = array(); - $oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria()); - $oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, array(), true /* main query */); + $aModifierProperties = self::MakeModifierProperties($oFilter); + $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties); + $oSelect = self::MakeQuery($oBuild, $oFilter, null, array(), true /* main query */); $aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams()); return $oSelect->RenderDelete($aScalarArgs); } @@ -2151,26 +2184,21 @@ abstract class MetaModel public static function MakeUpdateQuery(DBObjectSearch $oFilter, $aValues, $aArgs = array()) { // $aValues is an array of $sAttCode => $value - $aClassAliases = array(); - $aTableAliases = array(); - $oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria()); - $oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, $aValues, true /* main query */); + $aModifierProperties = self::MakeModifierProperties($oFilter); + $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties); + $oSelect = self::MakeQuery($oBuild, $oFilter, null, $aValues, true /* main query */); $aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams()); return $oSelect->RenderUpdate($aScalarArgs); } - private static function MakeQuery($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false) + private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false) { // Note: query class might be different than the class of the filter // -> this occurs when we are linking our class to an external class (referenced by, or pointing to) $sClass = $oFilter->GetFirstJoinedClass(); $sClassAlias = $oFilter->GetFirstJoinedClassAlias(); - $bIsOnQueriedClass = array_key_exists($sClassAlias, $aSelectedClasses); - if ($bIsOnQueriedClass) - { - $aClassAliases = array_merge($aClassAliases, $oFilter->GetJoinedClasses()); - } + $bIsOnQueriedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); self::DbgTrace("Entering: ".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY")); @@ -2180,7 +2208,7 @@ abstract class MetaModel if ($bIsOnQueriedClass) { // default to the whole list of attributes + the very std id/finalclass - $oQBExpr->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias)); + $oBuild->m_oQBExpressions->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias)); if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad)) { @@ -2196,7 +2224,7 @@ abstract class MetaModel foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { - $oQBExpr->AddSelect($sClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias)); + $oBuild->m_oQBExpressions->AddSelect($sClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias)); } } @@ -2216,14 +2244,14 @@ abstract class MetaModel foreach($aFullText as $sFTNeedle) { $oNewCond = new BinaryExpression($oTextFields, 'LIKE', new ScalarExpression("%$sFTNeedle%")); - $oQBExpr->AddCondition($oNewCond); + $oBuild->m_oQBExpressions->AddCondition($oNewCond); } } } -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; $aExpectedAtts = array(); // array of (attcode => fieldexpression) //echo "

".__LINE__.": GetUnresolvedFields($sClassAlias, ...)

\n"; - $oQBExpr->GetUnresolvedFields($sClassAlias, $aExpectedAtts); + $oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias, $aExpectedAtts); // Compute a clear view of required joins (from the current class) // Build the list of external keys: @@ -2260,9 +2288,9 @@ abstract class MetaModel { $aTranslateNow = array(); $aTranslateNow[$sClassAlias]['friendlyname'] = self::GetNameExpression($sClass, $sClassAlias); -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; - $oQBExpr->Translate($aTranslateNow, false); -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; + $oBuild->m_oQBExpressions->Translate($aTranslateNow, false); +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; $aNameSpec = self::GetNameSpec($sClass); foreach($aNameSpec[1] as $i => $sAttCode) @@ -2304,7 +2332,7 @@ abstract class MetaModel self::DbgTrace("Main (=leaf) class, call MakeQuerySingleTable()"); if (self::HasTable($sClass)) { - $oSelectBase = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sClass, $aExtKeys, $aValues); + $oSelectBase = self::MakeQuerySingleTable($oBuild, $oFilter, $sClass, $aExtKeys, $aValues); } else { @@ -2313,7 +2341,7 @@ abstract class MetaModel // As the join will not filter on the expected classes, we have to specify it explicitely $sExpectedClasses = implode("', '", self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL)); $oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')"); - $oQBExpr->AddCondition($oFinalClassRestriction); + $oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction); } // Then we join the queries of the eventual parent classes (compound model) @@ -2322,7 +2350,7 @@ abstract class MetaModel if (!self::HasTable($sParentClass)) continue; //echo "

Parent class: $sParentClass... let's call MakeQuerySingleTable()

"; self::DbgTrace("Parent class: $sParentClass... let's call MakeQuerySingleTable()"); - $oSelectParentTable = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sParentClass, $aExtKeys, $aValues); + $oSelectParentTable = self::MakeQuerySingleTable($oBuild, $oFilter, $sParentClass, $aExtKeys, $aValues); if (is_null($oSelectBase)) { $oSelectBase = $oSelectParentTable; @@ -2347,11 +2375,11 @@ abstract class MetaModel //self::DbgTrace($oSelectForeign->RenderSelect(array())); $sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias(); - $oQBExpr->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias)); + $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias)); - $oSelectForeign = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oForeignFilter, $aAttToLoad); + $oSelectForeign = self::MakeQuery($oBuild, $oForeignFilter, $aAttToLoad); - $oJoinExpr = $oQBExpr->PopJoinField(); + $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sForeignKeyTable = $oJoinExpr->GetParent(); $sForeignKeyColumn = $oJoinExpr->GetName(); $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable); @@ -2390,8 +2418,8 @@ abstract class MetaModel // if ($bIsMainQuery) { - $oSelectBase->SetCondition($oQBExpr->GetCondition()); - $oSelectBase->SetSelect($oQBExpr->GetSelect()); + $oSelectBase->SetCondition($oBuild->m_oQBExpressions->GetCondition()); + $oSelectBase->SetSelect($oBuild->m_oQBExpressions->GetSelect()); } // That's all... cross fingers and we'll get some working query @@ -2402,7 +2430,7 @@ abstract class MetaModel return $oSelectBase; } - protected static function MakeQuerySingleTable($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, $oFilter, $sTableClass, $aExtKeys, $aValues) + protected static function MakeQuerySingleTable(&$oBuild, $oFilter, $sTableClass, $aExtKeys, $aValues) { // $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields)) //echo "MAKEQUERY($sTableClass)-liste des clefs externes($sTableClass):
".print_r($aExtKeys, true)."

\n"; @@ -2416,13 +2444,13 @@ abstract class MetaModel $sTargetClass = $oFilter->GetFirstJoinedClass(); $sTargetAlias = $oFilter->GetFirstJoinedClassAlias(); $sTable = self::DBGetTable($sTableClass); - $sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTargetAlias.'_'.$sTable, $sTable); + $sTableAlias = $oBuild->GenerateTableAlias($sTargetAlias.'_'.$sTable, $sTable); $aTranslation = array(); $aExpectedAtts = array(); - $oQBExpr->GetUnresolvedFields($sTargetAlias, $aExpectedAtts); + $oBuild->m_oQBExpressions->GetUnresolvedFields($sTargetAlias, $aExpectedAtts); - $bIsOnQueriedClass = array_key_exists($sTargetAlias, $aSelectedClasses); + $bIsOnQueriedClass = array_key_exists($sTargetAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); self::DbgTrace("Entering: tableclass=$sTableClass, filter=".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY")); @@ -2471,6 +2499,18 @@ abstract class MetaModel $aUpdateValues[$sColumn] = $sValue; } } + } + + // 2 - The SQL query, for this table only + // + $oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField); + + // 3 - Resolve expected expressions (translation table: alias.attcode => table.column) + // + foreach(self::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) + { + // Skip this attribute if not defined in this table + if (self::$m_aAttribOrigins[$sTargetClass][$sAttCode] != $sTableClass) continue; // Select... // @@ -2487,16 +2527,17 @@ abstract class MetaModel { if (array_key_exists($sAttCode, $aExpectedAtts)) { - $aTranslation[$sTargetAlias][$sAttCode.$sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias); + $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; } } } } - // 3 - The whole stuff, for this table only - // - $oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField); - //echo "MAKEQUERY- Classe $sTableClass
\n"; // 4 - The external keys -> joins... // @@ -2516,7 +2557,7 @@ abstract class MetaModel // The join was not explicitely defined in the filter, // we need to do it now $sKeyClass = $oKeyAttDef->GetTargetClass(); - $sKeyClassAlias = self::GenerateUniqueAlias($aClassAliases, $sKeyClass.'_'.$sKeyAttCode, $sKeyClass); + $sKeyClassAlias = $oBuild->GenerateClassAlias($sKeyClass.'_'.$sKeyAttCode, $sKeyClass); $oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias); $aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter; @@ -2573,18 +2614,18 @@ abstract class MetaModel } // Translate prior to recursing // -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."\n".print_r($aTranslateNow, true)."

\n"; - $oQBExpr->Translate($aTranslateNow, false); -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."\n".print_r($aTranslateNow, true)."

\n"; + $oBuild->m_oQBExpressions->Translate($aTranslateNow, false); +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; //echo "

External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()/p>\n"; self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()"); - $oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias)); + $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression('id', $sKeyClassAlias)); -//echo "

Recursive MakeQuery ".__LINE__.":

\n".print_r($aSelectedClasses, true)."

\n"; - $oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter); +//echo "

Recursive MakeQuery ".__LINE__.":

\n".print_r($oBuild->GetRootFilter()->GetSelectedClasses(), true)."

\n"; + $oSelectExtKey = self::MakeQuery($oBuild, $oExtFilter); - $oJoinExpr = $oQBExpr->PopJoinField(); + $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); @@ -2604,9 +2645,9 @@ abstract class MetaModel } elseif(self::$m_aAttribOrigins[$sKeyClass][$sKeyAttCode] == $sTableClass) { - $oQBExpr->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias)); - $oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter); - $oJoinExpr = $oQBExpr->PopJoinField(); + $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias)); + $oSelectExtKey = self::MakeQuery($oBuild, $oExtFilter); + $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); //echo "MAKEQUERY-PopJoinField pour $sKeyAttCode, $sKeyClassAlias:
".print_r($oJoinExpr, true)."

\n"; $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); @@ -2625,9 +2666,9 @@ abstract class MetaModel // Translate the selected columns // -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; - $oQBExpr->Translate($aTranslation, false); -//echo "

oQBExpr ".__LINE__.":

\n".print_r($oQBExpr, true)."

\n"; +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; + $oBuild->m_oQBExpressions->Translate($aTranslation, false); +//echo "

oQBExpr ".__LINE__.":

\n".print_r($oBuild->m_oQBExpressions, true)."

\n"; //MyHelpers::var_dump_html($oSelectBase->RenderSelect()); return $oSelectBase; @@ -4660,7 +4701,7 @@ abstract class MetaModel } /** - * Returns an array of classes implementing the given interface + * Returns an array of classes=>instance implementing the given interface */ public static function EnumPlugins($sInterface) { @@ -4743,5 +4784,4 @@ MetaModel::RegisterZList("preview", array("description"=>"All attributes visible MetaModel::RegisterZList("standard_search", array("description"=>"List of criteria for the standard search", "type"=>"filters")); MetaModel::RegisterZList("advanced_search", array("description"=>"List of criteria for the advanced search", "type"=>"filters")); - -?> +?> \ No newline at end of file diff --git a/core/querybuildercontext.class.inc.php b/core/querybuildercontext.class.inc.php new file mode 100644 index 000000000..8c6e88544 --- /dev/null +++ b/core/querybuildercontext.class.inc.php @@ -0,0 +1,74 @@ + MakeQuery/MakeQuerySingleTable + * + * @author Erwan Taloc + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL + */ + +class QueryBuilderContext +{ + protected $m_oRootFilter; + protected $m_aClassAliases; + protected $m_aTableAliases; + protected $m_aModifierProperties; + + public $m_oQBExpressions; + + public function __construct($oFilter, $aModifierProperties) + { + $this->m_oRootFilter = $oFilter; + $this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria()); + + $this->m_aClassAliases = $oFilter->GetJoinedClasses(); + $this->m_aTableAliases = array(); + + $this->m_aModifierProperties = $aModifierProperties; + } + + public function GetRootFilter() + { + return $this->m_oRootFilter; + } + + public function GenerateTableAlias($sNewName, $sRealName) + { + return MetaModel::GenerateUniqueAlias($this->m_aTableAliases, $sNewName, $sRealName); + } + + public function GenerateClassAlias($sNewName, $sRealName) + { + return MetaModel::GenerateUniqueAlias($this->m_aClassAliases, $sNewName, $sRealName); + } + + public function GetModifierProperties($sPluginClass) + { + if (array_key_exists($sPluginClass, $this->m_aModifierProperties)) + { + return $this->m_aModifierProperties[$sPluginClass]; + } + else + { + return array(); + } + } +} + +?> \ No newline at end of file diff --git a/core/querymodifier.class.inc.php b/core/querymodifier.class.inc.php new file mode 100644 index 000000000..8fdfcf6cc --- /dev/null +++ b/core/querymodifier.class.inc.php @@ -0,0 +1,33 @@ + + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL + */ + +interface iQueryModifier +{ + public function __construct(); + + public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect); +} +?> diff --git a/core/sqlquery.class.inc.php b/core/sqlquery.class.inc.php index e39c89b81..582206573 100644 --- a/core/sqlquery.class.inc.php +++ b/core/sqlquery.class.inc.php @@ -68,6 +68,11 @@ class SQLQuery $this->m_oSelectedIdField = $oSelectedIdField; } + public function GetTableAlias() + { + return $this->m_sTableAlias; + } + public function SetSourceOQL($sOQL) { $this->m_SourceOQL = $sOQL; @@ -101,11 +106,20 @@ class SQLQuery { $sJoinType = $aJoinInfo["jointype"]; $oSQLQuery = $aJoinInfo["select"]; - $sLeftField = $aJoinInfo["leftfield"]; - $sRightField = $aJoinInfo["rightfield"]; - $sRightTableAlias = $aJoinInfo["righttablealias"]; + if (isset($aJoinInfo["on_expression"])) + { + $sOnCondition = $aJoinInfo["on_expression"]->Render(); - echo "
  • Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."
  • \n"; + echo "
  • Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."
  • \n"; + } + else + { + $sLeftField = $aJoinInfo["leftfield"]; + $sRightField = $aJoinInfo["rightfield"]; + $sRightTableAlias = $aJoinInfo["righttablealias"]; + + echo "
  • Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."
  • \n"; + } } echo ""; } @@ -196,6 +210,24 @@ class SQLQuery { return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField); } + + public function AddInnerJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression) + { + $this->m_aJoinSelects[] = array( + "jointype" => 'inner', + "select" => $oSQLQuery, + "on_expression" => $oOnExpression + ); + } + + public function AddLeftJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression) + { + $this->m_aJoinSelects[] = array( + "jointype" => 'left', + "select" => $oSQLQuery, + "on_expression" => $oOnExpression + ); + } // Interface, build the SQL query public function RenderDelete($aArgs = array()) @@ -412,8 +444,14 @@ class SQLQuery break; case "inner": case "left": - // table or tablealias ??? - $sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`"; + if (isset($aJoinData["on_expression"])) + { + $sJoinCond = $aJoinData["on_expression"]->Render(); + } + else + { + $sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`"; + } $aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond"); break; case "inner_tree": @@ -488,10 +526,6 @@ class SQLQuery foreach ($this->m_aJoinSelects as $aJoinData) { $oRightSelect = $aJoinData["select"]; -// $sJoinType = $aJoinData["jointype"]; -// $sLeftField = $aJoinData["leftfield"]; -// $sRightField = $aJoinData["rightfield"]; -// $sRightTableAlias = $aJoinData["righttablealias"]; $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData); } diff --git a/pages/csvimport.php b/pages/csvimport.php index bd64ee5b2..3264fb168 100644 --- a/pages/csvimport.php +++ b/pages/csvimport.php @@ -304,6 +304,9 @@ try $sUserString .= ' (CSV)'; $oMyChange->Set("userinfo", $sUserString); $iChangeId = $oMyChange->DBInsert(); + + // Todo - simplify that when reworking the change tracking + CMDBObject::SetCurrentChange($oMyChange); } $oBulk = new BulkChange(