oDBObjetSearch = $oDBObjetSearch; } /** * @param array $aAttToLoad * @param bool $bGetCount * @param array $aModifierProperties * @param array $aGroupByExpr * @param array $aSelectedClasses * @param array $aSelectExpr * * @return null|SQLObjectQuery * @throws \CoreException */ public function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null) { if ($bGetCount || !is_null($aGroupByExpr)) { // Avoid adding all the fields for counts or "group by" requests $aAttToLoad = array(); foreach ($this->oDBObjetSearch->GetSelectedClasses() as $sClassAlias => $sClass) { $aAttToLoad[$sClassAlias] = array(); } } $oBuild = new QueryBuilderContext($this->oDBObjetSearch, $aModifierProperties, $aGroupByExpr, $aSelectedClasses, $aSelectExpr, $aAttToLoad); $oSQLQuery = $this->MakeSQLObjectQueryRoot($oBuild, array(), $aGroupByExpr, $aSelectExpr); return $oSQLQuery; } /** * @return \SQLObjectQuery|null * @throws \CoreException */ public function MakeSQLObjectDeleteQuery() { $aModifierProperties = MetaModel::MakeModifierProperties($this->oDBObjetSearch); $aAttToLoad = array($this->oDBObjetSearch->GetClassAlias() => array()); $oBuild = new QueryBuilderContext($this->oDBObjetSearch, $aModifierProperties, null, null, null, $aAttToLoad); $oSQLQuery = $this->MakeSQLObjectQueryRoot($oBuild, array()); return $oSQLQuery; } /** * @param array $aValues an array of $sAttCode => $value * * @return \SQLObjectQuery|null * @throws \CoreException */ public function MakeSQLObjectUpdateQuery($aValues) { $aModifierProperties = MetaModel::MakeModifierProperties($this->oDBObjetSearch); $aRequested = array(); // Requested attributes are the updated attributes foreach ($aValues as $sAttCode => $value) { $aRequested[$sAttCode] = MetaModel::GetAttributeDef($this->oDBObjetSearch->GetClass(), $sAttCode); } $aAttToLoad = array($this->oDBObjetSearch->GetClassAlias() => $aRequested); $oBuild = new QueryBuilderContext($this->oDBObjetSearch, $aModifierProperties, null, null, null, $aAttToLoad); $oSQLQuery = $this->MakeSQLObjectQueryRoot($oBuild, $aValues); return $oSQLQuery; } /** * @param \QueryBuilderContext $oBuild * * @return \OQLClassNode * @throws \CoreException */ private function GetOQLClassTree($oBuild) { $oOQLClassTreeBuilder = new OQLClassTreeBuilder($this->oDBObjetSearch, $oBuild); $oOQLClassNode = $oOQLClassTreeBuilder->DevelopOQLClassNode(); $oOQLClassTreeOptimizer = new OQLClassTreeOptimizer($oOQLClassNode, $oBuild); $oOQLClassTreeOptimizer->OptimizeClassTree(); $oOQLActualClassTreeResolver = new OQLActualClassTreeResolver($oOQLClassNode, $oBuild); $oOQLClassNode = $oOQLActualClassTreeResolver->Resolve(); return $oOQLClassNode; } /** * @param \QueryBuilderContext $oBuild * @param array $aValues * @param array $aGroupByExpr * @param array $aSelectExpr * * @return null|SQLObjectQuery * @throws \CoreException */ private function MakeSQLObjectQueryRoot($oBuild, $aValues = array(), $aGroupByExpr = null, $aSelectExpr = null) { $oOQLClassNode = $this->GetOQLClassTree($oBuild); $oSQLQuery = $this->MakeSQLObjectQuery($oBuild, $oOQLClassNode, $aValues); /** * Add SQL Level additional information */ $oSQLQuery->SetCondition($oBuild->m_oQBExpressions->GetCondition()); if (is_array($aGroupByExpr)) { $aCols = $oBuild->m_oQBExpressions->GetGroupBy(); $oSQLQuery->SetGroupBy($aCols); $oSQLQuery->SetSelect($aCols); if (!empty($aSelectExpr)) { // Get the fields corresponding to the select expressions foreach($oBuild->m_oQBExpressions->GetSelect() as $sAlias => $oExpr) { if (key_exists($sAlias, $aSelectExpr)) { $oSQLQuery->AddSelect($sAlias, $oExpr); } } } } else { $oSQLQuery->SetSelect($oBuild->m_oQBExpressions->GetSelect()); } // Filter for archive flag // Filter tables as late as possible: do not interfere with the optimization process $aMandatoryTables = $oBuild->m_oQBExpressions->GetMandatoryTables(); foreach ($oBuild->GetFilteredTables() as $sTableAlias => $aConditions) { if ($aMandatoryTables && array_key_exists($sTableAlias, $aMandatoryTables)) { foreach ($aConditions as $oCondition) { $oSQLQuery->AddCondition($oCondition); } } } return $oSQLQuery; } /** * @param \QueryBuilderContext $oBuild * @param \OQLClassNode $oOQLClassNode * @param array $aValues * * @return \SQLObjectQuery * @throws \CoreException */ private function MakeSQLObjectQuery($oBuild, $oOQLClassNode, $aValues) { $oSQLQuery = $this->MakeSQLObjectQueryNode($oBuild, $oOQLClassNode, $aValues); return $oSQLQuery; } /** * @param \QueryBuilderContext $oBuild * @param \OQLClassNode $oOQLClassNode * @param array $aValues * * @return \SQLObjectQuery * @throws \CoreException */ private function MakeSQLObjectQueryNode($oBuild, $oOQLClassNode, $aValues) { $sClass = $oOQLClassNode->GetNodeClass(); $sTable = MetaModel::DBGetTable($sClass); $sClassAlias = $oOQLClassNode->GetNodeClassAlias(); $sSelectedClassAlias = $oOQLClassNode->GetOQLClassAlias(); $bIsOnQueriedClass = array_key_exists($sSelectedClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); $aExpectedAttributes = $oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias); $oSelectedIdField = null; $aTranslation = array(); $aUpdateValues = array(); $oIdField = new FieldExpressionResolved(MetaModel::DBGetKey($sClass), $sClassAlias); $aTranslation[$sClassAlias]['id'] = $oIdField; if ($bIsOnQueriedClass) { // Add this field to the list of queried fields (required for the COUNT to work fine) $oSelectedIdField = $oIdField; foreach ($aExpectedAttributes as $sAttCode => $oExpression) { if (!array_key_exists($sAttCode, $aValues)) { continue; } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); // Skip this attribute if not made of SQL columns if (count($oAttDef->GetSQLExpressions()) == 0) { continue; } foreach ($oAttDef->GetSQLValues($aValues[$sAttCode]) as $sColumn => $sValue) { $aUpdateValues[$sColumn] = $sValue; } } } $oBaseSQLQuery = new SQLObjectQuery($sTable, $sClassAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField); foreach ($aExpectedAttributes as $sAttCode => $oExpression) { if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { continue; } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { if (!empty($sColId)) { // Multi column attributes $oBuild->m_oQBExpressions->AddSelect($sSelectedClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias)); } $oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sClassAlias); foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) { $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sClass, $sAttCode, $sColId, $oFieldSQLExp, $oBaseSQLQuery); } $aTranslation[$sClassAlias][$sAttCode.$sColId] = $oFieldSQLExp; } } // Translate the selected columns // $oBuild->m_oQBExpressions->Translate($aTranslation, false); // Filter out archived records // if (MetaModel::IsArchivable($sClass)) { if (!$oBuild->GetRootFilter()->GetArchiveMode()) { $bIsOnJoinedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetJoinedClasses()); if ($bIsOnJoinedClass) { $oNotArchived = new BinaryExpression(new FieldExpressionResolved('archive_flag', $sClassAlias), '=', new ScalarExpression(0)); $oBuild->AddFilteredTable($sClassAlias, $oNotArchived); } } } // Add Joins $aJoins = $oOQLClassNode->GetJoins(); foreach ($aJoins as $aJoin) { foreach ($aJoin as $oOQLJoin) { $oJoinedClassNode = $oOQLJoin->GetOOQLClassNode(); $oJoinedSQLQuery = $this->MakeSQLObjectQueryNode($oBuild, $oJoinedClassNode, $aValues); $oOQLJoin->AddToSQLObjectQuery($oBuild, $oBaseSQLQuery, $oJoinedSQLQuery); } } return $oBaseSQLQuery; } }