diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 099615ee7..810e2fd9a 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -6990,25 +6990,29 @@ abstract class MetaModel * @param string $sClass * @param int $iKey * - * @return bool True if the object of $sClass and $iKey exists in the DB, false otherwise meaning: + * @return bool True if the object of $sClass and $iKey exists in the DB -no matter the current user restrictions-, false otherwise meaning: * - It could be in memory for now and is not persisted yet * - It is neither in memory nor DB * * @throws \CoreException - * @throws \MissingQueryArgument * @throws \MySQLException - * @throws \MySQLHasGoneAwayException - * @throws \OQLException - * + * @throws \MySQLQueryHasNoResultException * @since 3.0.0 N°4173 */ public static function IsObjectInDB(string $sClass, int $iKey): bool { - $oFilter = DBObjectSearch::FromOQL('SELECT '.$sClass.' WHERE id = :id', ['id' => $iKey,]); - $oSet = new DBObjectSet($oFilter); - $iCount = $oSet->Count(); + // Note: We take the root class to ensure that there is a corresponding table in the DB + // as some intermediate classes can have no table in the DB. + $sRootClass = MetaModel::GetRootClass($sClass); - return ($iCount > 0); + $sTable = MetaModel::DBGetTable($sRootClass); + $sKeyCol = MetaModel::DBGetKey($sRootClass); + $sEscapedKey = CMDBSource::Quote($iKey); + + $sQuery = "SELECT count(*) FROM `{$sTable}` WHERE `{$sKeyCol}` = {$sEscapedKey}"; + $iCount = (int) CMDBSource::QueryToScalar($sQuery); + + return $iCount === 1; } /** diff --git a/test/core/MetaModelTest.php b/test/core/MetaModelTest.php index 84dd249c7..d9b33fa6a 100644 --- a/test/core/MetaModelTest.php +++ b/test/core/MetaModelTest.php @@ -180,7 +180,6 @@ class MetaModelTest extends ItopDataTestCase } } - /** * @dataProvider enumPluginsProvider * @@ -273,7 +272,6 @@ class MetaModelTest extends ItopDataTestCase return $aInterfaces; } - /** * @group itopRequestMgmt * @dataProvider GetEnumStyleProvider @@ -335,6 +333,35 @@ class MetaModelTest extends ItopDataTestCase ['lnkPersonToTeam', true], ]; } + + /** + * @covers \MetaModel::IsObjectInDB + * @dataProvider IsObjectInDBProvider + * + * @param int $iKeyOffset Offset to apply on the key of the test object. This is necessary to test an object that doesn't exist yet in any DB as we can't know what is the last existing object key. + * @param $bExpectedResult + * + * @throws \CoreException + * @throws \MySQLException + * @throws \MySQLQueryHasNoResultException + */ + public function testIsObjectInDB(int $iKeyOffset, $bExpectedResult) + { + $oPerson = $this->CreatePerson(1, 1); + $sClass = get_class($oPerson); + $iKey = $oPerson->GetKey() + $iKeyOffset; + + $bTestResult = MetaModel::IsObjectInDB($sClass, $iKey); + $this->assertEquals($bTestResult, $bExpectedResult); + } + + public function IsObjectInDBProvider(): array + { + return [ + 'Existing person' => [0, true], + 'Non existing person' => [10, false], + ]; + } } abstract class Wizzard