N°6968 - Audit duration : add of a rule multiplie by 4 the time of response (#575)

This commit is contained in:
Anne-Catherine
2024-02-29 16:18:03 +01:00
committed by Anne-Cath
parent f6fec506b1
commit 473cf004b6
4 changed files with 180 additions and 38 deletions

View File

@@ -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

View File

@@ -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];
}

View File

@@ -1,20 +1,7 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
/*
* @copyright Copyright (C) 2010-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
@@ -113,7 +100,7 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext)
{
// The query returns only the valid elements, all the others are invalid
// Warning : we're generating a `WHERE ID IN`... query, and this could be very slow if there are lots of id !
$aValidRows = $oRuleFilter->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("<div id=\"$sBlockId\" style=\"clear:both\">\n");
$oBlock = DisplayBlock::FromObjectSet($oErrorObjectSet, 'csv', array('show_obsolete_data' => true));
$oBlock->Display($oP, 1);
$oP->p("</div>\n");
$oP->p("</div>\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'] = "<a href=\"audit.php?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."\">0</a>";
$aRow['nb_errors'] = "<a href=\"audit.php?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."\">0</a>";
$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' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a> <a href=\"?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">(CSV)</a>";
$aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a> <a href=\"?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">(CSV)</a>";
$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("<img style=\"vertical-align:middle\" src=\"../images/stop-mid.png\"/>&nbsp;".$sMessage);
$aResults[] = $aRow;
$aResults[] = $aRow;
$sClass = 'red';
$iTotalErrors = 'n/a';

View File

@@ -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');
}
}