From 473cf004b668225f55795469628051dc52ce7733 Mon Sep 17 00:00:00 2001 From: Anne-Catherine <57360138+accognet@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:18:03 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B06968=20-=20Audit=20duration=20:=20add=20?= =?UTF-8?q?of=20a=20rule=20multiplie=20by=204=20the=20time=20of=20response?= =?UTF-8?q?=20(#575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/dbsearch.class.php | 59 +++++++++- core/userrights.class.inc.php | 4 +- pages/audit.php | 47 +++----- .../unitary-tests/core/DBSearchTest.php | 108 +++++++++++++++++- 4 files changed, 180 insertions(+), 38 deletions(-) diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php index 1dbe02c44..95b1f8256 100644 --- a/core/dbsearch.class.php +++ b/core/dbsearch.class.php @@ -866,11 +866,11 @@ abstract class DBSearch return; } - if (count($aColumns) == 0) - { - $aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass())); - // Add the standard id (as first column) - array_unshift($aColumns, 'id'); + if (count($aColumns) == 0) + { + $aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass())); + // Add the standard id (as first column) + array_unshift($aColumns, 'id'); } $aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL); @@ -900,6 +900,55 @@ abstract class DBSearch return $aRes; } + /** + * Selects a column ($sAttCode) from the specified class ($sClassAlias - default main class) of the DBsearch object and gives the result as an array + * @param string $sAttCode + * @param string|null $sClassAlias + * + * @return array + * @throws ConfigException + * @throws CoreException + * @throws MissingQueryArgument + * @throws MySQLException + * @throws MySQLHasGoneAwayException + */ + public function SelectAttributeToArray(string $sAttCode, ?string $sClassAlias = null):array + { + if(is_null($sClassAlias)) { + $sClassAlias = $this->GetClassAlias(); + } + + $sClass = $this->GetClass(); + if($sAttCode === 'id'){ + $aAttToLoad[$sClassAlias]=[]; + } else { + $aAttToLoad[$sClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sClass, $sAttCode); + } + + $sSQL = $this->MakeSelectQuery([], [], $aAttToLoad); + $resQuery = CMDBSource::Query($sSQL); + if (!$resQuery) + { + return []; + } + + $sColName = $sClassAlias.$sAttCode; + + $aRes = []; + while ($aRow = CMDBSource::FetchArray($resQuery)) + { + $aMappedRow = array(); + if($sAttCode === 'id') { + $aMappedRow[$sAttCode] = $aRow[$sColName]; + } else { + $aMappedRow[$sAttCode] = $aAttToLoad[$sClassAlias][$sAttCode]->FromSQLToValue($aRow, $sColName); + } + $aRes[] = $aMappedRow; + } + CMDBSource::FreeResult($resQuery); + return $aRes; + } + //////////////////////////////////////////////////////////////////////////// // // Construction of the SQL queries diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index f40f1209e..cc0cffd50 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -110,7 +110,7 @@ abstract class UserRightsAddOnAPI $oSearchSharers->AllowAllData(); $oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id'); $aSharers = array(); - foreach($oSearchSharers->ToDataArray(array('id')) as $aRow) + foreach($oSearchSharers->SelectAttributeToArray('id') as $aRow) { $aSharers[] = $aRow['id']; } @@ -135,7 +135,7 @@ abstract class UserRightsAddOnAPI $oOrgField = new FieldExpression('org_id', $sShareClass); $oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr)); $aShared = array(); - foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow) + foreach($oSearchShares->SelectAttributeToArray($sShareAttCode) as $aRow) { $aShared[] = $aRow[$sShareAttCode]; } diff --git a/pages/audit.php b/pages/audit.php index 7a055b479..2a3815983 100644 --- a/pages/audit.php +++ b/pages/audit.php @@ -1,20 +1,7 @@ ToDataArray(array('id')); + $aValidRows = $oRuleFilter->ToDataArray(array('id')); $aValidIds = array(); foreach($aValidRows as $aRow) { @@ -163,7 +150,7 @@ try require_once(APPROOT.'/application/itopwebpage.class.inc.php'); require_once(APPROOT.'/application/csvpage.class.inc.php'); - + require_once(APPROOT.'/application/startup.inc.php'); $operation = utils::ReadParam('operation', ''); $oAppContext = new ApplicationContext(); @@ -232,7 +219,7 @@ try $oP->p("
\n"); $oBlock = DisplayBlock::FromObjectSet($oErrorObjectSet, 'csv', array('show_obsolete_data' => true)); $oBlock->Display($oP, 1); - $oP->p("
\n"); + $oP->p("\n"); // Adjust the size of the Textarea containing the CSV to fit almost all the remaining space $oP->add_ready_script(" $('#1>textarea').height(400);"); // adjust the size of the block $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey(); @@ -246,7 +233,7 @@ try $oP->SetBreadCrumbEntry('ui-tool-auditerrors', $sTitle, '', '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png'); $iCategory = utils::ReadParam('category', ''); $iRuleIndex = utils::ReadParam('rule', 0); - + $oAuditCategory = MetaModel::GetObject('AuditCategory', $iCategory); $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); $oDefinitionFilter->UpdateContextFromUser(); @@ -265,7 +252,7 @@ try $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey(); $oP->add_ready_script("$('a[href*=\"pages/UI.php?operation=search\"]').attr('href', '".$sExportUrl."')"); break; - + case 'audit': default: $oP->SetBreadCrumbEntry('ui-tool-audit', Dict::S('Menu:Audit'), Dict::S('UI:Audit:InteractiveAudit'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png'); @@ -286,7 +273,7 @@ try $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); $oDefinitionFilter->UpdateContextFromUser(); FilterByContext($oDefinitionFilter, $oAppContext); - + $aObjectsWithErrors = array(); if (!empty($currentOrganization)) { @@ -308,7 +295,7 @@ try if ($iCount == 0) { // nothing to check, really ! - $aRow['nb_errors'] = "GetKey()."&rule=".$oAuditRule->GetKey()."\">0"; + $aRow['nb_errors'] = "GetKey()."&rule=".$oAuditRule->GetKey()."\">0"; $aRow['percent_ok'] = '100.00'; $aRow['class'] = GetReportColor($iCount, 0); } @@ -317,19 +304,19 @@ try try { $oFilter = GetRuleResultFilter($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext); - $aErrors = $oFilter->ToDataArray(array('id')); + $aErrors = $oFilter->SelectAttributeToArray('id'); $iErrorsCount = count($aErrors); foreach($aErrors as $aErrorRow) { $aObjectsWithErrors[$aErrorRow['id']] = true; } - $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">(CSV)"; + $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">(CSV)"; $aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount)); - $aRow['class'] = GetReportColor($iCount, $iErrorsCount); + $aRow['class'] = GetReportColor($iCount, $iErrorsCount); } catch(Exception $e) { - $aRow['nb_errors'] = "OQL Error"; + $aRow['nb_errors'] = "OQL Error"; $aRow['percent_ok'] = 'n/a'; $aRow['class'] = 'red'; $sMessage = Dict::Format('UI:Audit:ErrorIn_Rule_Reason', $oAuditRule->GetHyperlink(), $e->getMessage()); @@ -346,12 +333,12 @@ try { $aRow = array(); $aRow['description'] = "OQL error"; - $aRow['nb_errors'] = "n/a"; + $aRow['nb_errors'] = "n/a"; $aRow['percent_ok'] = ''; - $aRow['class'] = 'red'; + $aRow['class'] = 'red'; $sMessage = Dict::Format('UI:Audit:ErrorIn_Category_Reason', $oAuditCategory->GetHyperlink(), utils::HtmlEntities($e->getMessage())); $oP->p(" ".$sMessage); - $aResults[] = $aRow; + $aResults[] = $aRow; $sClass = 'red'; $iTotalErrors = 'n/a'; diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php index 5d00b6aa5..7199e6361 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php @@ -739,4 +739,110 @@ class DBSearchTest extends ItopDataTestCase $oSearch->MakeSelectQuery(); self::assertTrue(true); } -} + /** + * @dataProvider QueriesProvider + * @param $sOQL + * + * @return void + */ + public function testQueries($sOQL) + { + $oSearch = DBSearch::FromOQL($sOQL); + $oSet = new DBObjectSet($oSearch); + if ($oSet->Count() > 0) { + $aSelectedAliases = array_keys($oSearch->GetSelectedClasses()); + $aFirstRow = $oSet->FetchAssoc(); + $aAliases = array_keys($aFirstRow); + $this->assertEquals($aSelectedAliases, $aAliases); + } + } + + public function QueriesProvider() + { + return [ + ['SELECT L,P FROM Person AS P JOIN Location AS L ON P.location_id=L.id'], + ['SELECT P,L FROM Person AS P JOIN Location AS L ON P.location_id=L.id'], + ]; + } + public function SelectAttributeToArrayProvider() + { + return array( + 'select id from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'id', + ), + 'select name from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'name', + ), + 'select org_id from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'org_id', + ), + 'select organization_name from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'organization_name', + ), + 'select business_criticity from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'business_criticity', + ), + 'select org_id from FunctionalCI' => array( + 'SELECT FunctionalCI', + 'org_id', + ), + 'select email from Person' => array( + 'SELECT Person', + 'email', + ), + 'select phone from Person' => array( + 'SELECT Person', + 'phone', + ), + 'select picture from Person' => array( + 'SELECT Person', + 'picture', + ), + 'select description from Ticket' => array( + 'SELECT Ticket', + 'description', + ), + 'select start_date from Ticket' => array( + 'SELECT Ticket', + 'start_date', + ), + 'select private_log from Ticket' => array( + 'SELECT Ticket', + 'private_log', + ), + ); + } + + /** + * @dataProvider SelectAttributeToArrayProvider + * + * @return void + * @throws \ConfigException + * @throws \CoreException + * @throws \MissingQueryArgument + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + * @throws \OQLException + */ + public function testSelectAttributeToArray($sQuery, $sField){ + + $oSearch = \DBObjectSearch::FromOQL($sQuery); + $aResToDataArray=[]; + $oSet = new \DBObjectSet($oSearch); + while ($oRecord = $oSet->Fetch()) { + $aMappedRow[$sField] =$oRecord->Get($sField); + $aResToDataArray[] = $aMappedRow; + } + array_multisort (array_column($aResToDataArray, $sField), SORT_DESC, $aResToDataArray); + + $aResSelectColumnToArray = $oSearch->SelectAttributeToArray($sField); + array_multisort (array_column($aResSelectColumnToArray, $sField), SORT_DESC, $aResSelectColumnToArray); + + self::assertEquals( $aResToDataArray, $aResSelectColumnToArray, 'The array constructed using the OQL query and the result of testSelectAttributeToArray must be the same'); + } +} \ No newline at end of file