diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 8751a0d042..82c9f6cba2 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -7987,6 +7987,17 @@ class AttributeExternalField extends AttributeDefinition return $oExtAttDef->MakeRealValue($proposedValue, $oHostObj); } + /** + * @inheritDoc + * @since 3.1.0 N°6271 Delegate to remote attribute to ensure cascading computed values + */ + public function GetSQLValues($value) + { + $oExtAttDef = $this->GetExtAttDef(); + + return $oExtAttDef->GetSQLValues($value); + } + public function ScalarToSQL($value) { // This one could be used in case of filtering only diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 62603de165..9d9dda78e1 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -2853,11 +2853,10 @@ abstract class DBObject implements iDisplay $aHierarchicalKeys = array(); - foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) - { + foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) { // Skip this attribute if not defined in this table - if (!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode) && !$oAttDef->CopyOnAllTables()) - { + if ((!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode) && !$oAttDef->CopyOnAllTables()) + || $oAttDef->IsExternalField()) { continue; } $aAttColumns = $oAttDef->GetSQLValues($this->m_aCurrValues[$sAttCode]); @@ -2981,10 +2980,13 @@ abstract class DBObject implements iDisplay } $aHierarchicalKeys = array(); - foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) + foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table - if (!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode)) continue; + if ((!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode)) + || $oAttDef->IsExternalField()) { + continue; + }; // Skip link set that can still be undefined though the object is 100% loaded if ($oAttDef->IsLinkSet()) continue; @@ -6011,11 +6013,8 @@ abstract class DBObject implements iDisplay } $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); - $aSQLValues = $oAttDef->GetSQLValues($this->m_aCurrValues[$sAttCode]); + $aSQLValues = $oAttDef->GetSQLValues($this->Get($sAttCode)); $value = reset($aSQLValues); - if ($oAttDef->IsNull($value)) { - return ''; - } $aArgs[$sFieldDesc] = $value; } diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index 78a9636ddd..0a6db899e9 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -3526,6 +3526,7 @@ class CharConcatWSExpression extends CharConcatExpression $aRes = array(); foreach ($this->m_aExpressions as $oExpr) { + // TODO: Seems weird, this should rather be $aRes[] = $oExpr->Evaluate($aArgs); $aRes .= $oExpr->Evaluate($aArgs); } return implode($this->m_separator, $aRes); diff --git a/core/sqlobjectquerybuilder.class.inc.php b/core/sqlobjectquerybuilder.class.inc.php index 4b1ea37792..568e4b3435 100644 --- a/core/sqlobjectquerybuilder.class.inc.php +++ b/core/sqlobjectquerybuilder.class.inc.php @@ -218,8 +218,8 @@ class SQLObjectQueryBuilder continue; } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); - // Skip this attribute if not made of SQL columns - if (count($oAttDef->GetSQLExpressions()) == 0) + // Skip this attribute if not made of SQL columns nor in current table + if (count($oAttDef->GetSQLExpressions()) == 0 || $oAttDef->IsExternalField()) { continue; } diff --git a/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php b/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php index b19ec8acb9..23e9bd592d 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php @@ -140,7 +140,7 @@ class DBObjectTest extends ItopDataTestCase * @covers DBObject::Get * @covers DBObject::Set */ - public function testAttributeRefresh_FriendlyName() + public function testAttributeRefresh_FriendlyNameWithoutCascade() { $oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2)); @@ -149,6 +149,21 @@ class DBObjectTest extends ItopDataTestCase static::assertEquals('John Who', $oObject->Get('friendlyname')); } + /** + * @covers DBObject::NewObject + * @covers DBObject::Get + * @covers DBObject::Set + */ + public function testAttributeRefresh_FriendlyNameWithCascade() + { + $oServer = \MetaModel::NewObject('Server', ['name' => 'ServerTest', 'org_id' => 3]); + $oServer->DBInsert(); + $oDBServer = \MetaModel::NewObject('DBServer', ['name' => 'DBServerTest', 'org_id' => 3, 'system_id' => $oServer]); + + static::assertEquals('ServerTest', $oDBServer->Get('system_name')); + static::assertEquals('DBServerTest ServerTest', $oDBServer->Get('friendlyname')); + } + /** * @covers MetaModel::GetObject * @covers DBObject::Get @@ -174,8 +189,7 @@ class DBObjectTest extends ItopDataTestCase public function testPartialAttributeEvaluation() { $oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'org_id' => 3, 'location_id' => 2)); - - static::assertEquals('', $oObject->Get('friendlyname')); + static::assertEquals(' Foo', $oObject->Get('friendlyname')); } /** @@ -186,7 +200,7 @@ class DBObjectTest extends ItopDataTestCase { $oObject = \MetaModel::NewObject('Person', array('org_id' => 3, 'location_id' => 2)); - static::assertEquals('', $oObject->Get('friendlyname')); + static::assertEquals(' ', $oObject->Get('friendlyname')); } /** @@ -198,7 +212,7 @@ class DBObjectTest extends ItopDataTestCase $oUserProfile = new \URP_UserProfile(); $oUserProfile->Set('profileid', 2); - static::assertEquals('', $oUserProfile->Get('friendlyname')); + static::assertEquals('Link between and Portal user', $oUserProfile->Get('friendlyname')); } /** @@ -206,7 +220,7 @@ class DBObjectTest extends ItopDataTestCase * @covers DBObject::Get * @covers DBObject::Set */ - public function testAttributeRefresh_ObsolescenceFlag() + public function testAttributeRefresh_ObsolescenceFlagWithoutCascade() { $oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2)); @@ -215,6 +229,24 @@ class DBObjectTest extends ItopDataTestCase static::assertEquals(true, (bool)$oObject->Get('obsolescence_flag')); } + /** + * @covers DBObject::NewObject + * @covers DBObject::Get + * @covers DBObject::Set + */ + public function testAttributeRefresh_ObsolescenceFlagWithCascade() + { + $this->markTestSkipped('Postponed'); + // Necessary ext. key for $oDBServer + $oServer = \MetaModel::NewObject('Server', ['name' => 'ServerTest', 'org_id' => 3]); + $oServer->DBInsert(); + $oDBServer = \MetaModel::NewObject('DBServer', ['name' => 'DBServerTest', 'org_id' => 3, 'system_id' => $oServer, 'status' => 'inactive']); + $oDBServer->DBInsert(); + + $oDBSchema = \MetaModel::NewObject('DatabaseSchema', ['name' => 'DBSchemaTest', 'org_id' => 3, 'dbserver_id' => $oDBServer]); + static::assertEquals(true, $oDBSchema->Get('obsolescence_flag')); + } + /** * @covers DBObject::NewObject * @covers DBObject::Get