Merge remote-tracking branch 'origin/support/3.0' into develop

This commit is contained in:
Molkobain
2023-03-07 10:25:15 +01:00
4 changed files with 338 additions and 2 deletions

View File

@@ -3342,13 +3342,14 @@ EOF
// Consider only the "expected" fields for the target state
if (array_key_exists($sAttCode, $aExpectedAttributes)) {
$iExpectCode = $aExpectedAttributes[$sAttCode];
// Prompt for an attribute if
// - the attribute must be changed or must be displayed to the user for confirmation
// - or the field is mandatory and currently empty
if (($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
(($iExpectCode & OPT_ATT_MANDATORY) && ($this->Get($sAttCode) == ''))) {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
(($iExpectCode & OPT_ATT_MANDATORY) && (false === $this->HasAValue($sAttCode)))) {
$aArgs = array('this' => $this);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
// If the field is mandatory, set it to the only possible value
if ((!$oAttDef->IsNullAllowed()) || ($iExpectCode & OPT_ATT_MANDATORY)) {
if ($oAttDef->IsExternalKey()) {

View File

@@ -746,6 +746,18 @@ abstract class AttributeDefinition
return is_null($proposedValue);
}
/**
* @param mixed $proposedValue
*
* @return bool True if $proposedValue is an actual value set in the attribute, false is the attribute remains "empty"
* @since 3.0.3, 3.1.0 N°5784
*/
public function HasAValue($proposedValue): bool
{
// Default implementation, we don't really know what type $proposedValue will be
return is_null($proposedValue);
}
/**
* force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!
*
@@ -1430,6 +1442,15 @@ class AttributeDashboard extends AttributeDefinition
{
return '';
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
// Always return false for now, we don't consider a custom version of a dashboard
return false;
}
}
/**
@@ -2317,6 +2338,22 @@ class AttributeLinkedSet extends AttributeDefinition
{
return false;
}
/**
* @inheritDoc
* @param \ormLinkSet $proposedValue
*/
public function HasAValue($proposedValue): bool
{
// Protection against wrong value type
if (false === ($proposedValue instanceof ormLinkSet))
{
return parent::HasAValue($proposedValue);
}
// We test if there is at least 1 item in the linkset (new or existing), not if an item is being added to it.
return $proposedValue->Count() > 0;
}
}
/**
@@ -2714,6 +2751,14 @@ class AttributeInteger extends AttributeDBField
return is_null($proposedValue);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return utils::IsNotNullOrEmptyString($proposedValue);
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -2813,6 +2858,14 @@ class AttributeObjectKey extends AttributeDBFieldVoid
return ($proposedValue == 0);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return ((int) $proposedValue) !== 0;
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -3012,6 +3065,14 @@ class AttributeDecimal extends AttributeDBField
return is_null($proposedValue);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return utils::IsNotNullOrEmptyString($proposedValue);
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -3423,6 +3484,14 @@ class AttributeString extends AttributeDBField
return ($proposedValue == '');
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return utils::IsNotNullOrEmptyString($proposedValue);
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -4579,6 +4648,22 @@ class AttributeCaseLog extends AttributeLongText
return ($proposedValue->GetText() == '');
}
/**
* @inheritDoc
* @param \ormCaseLog $proposedValue
*/
public function HasAValue($proposedValue): bool
{
// Protection against wrong value type
if (false === ($proposedValue instanceof ormCaseLog)) {
return parent::HasAValue($proposedValue);
}
// We test if there is at least 1 entry in the log, not if the user is adding one
return $proposedValue->GetEntryCount() > 0;
}
public function ScalarToSQL($value)
{
if (!is_string($value) && !is_null($value))
@@ -6901,6 +6986,14 @@ class AttributeExternalKey extends AttributeDBFieldVoid
return ($proposedValue == 0);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return ((int) $proposedValue) !== 0;
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -7650,6 +7743,16 @@ class AttributeExternalField extends AttributeDefinition
return $oExtAttDef->IsNull($proposedValue);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
$oExtAttDef = $this->GetExtAttDef();
return $oExtAttDef->HasAValue($proposedValue);
}
public function MakeRealValue($proposedValue, $oHostObj)
{
$oExtAttDef = $this->GetExtAttDef();
@@ -8236,6 +8339,20 @@ class AttributeBlob extends AttributeDefinition
return $oFormField;
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
if (false === ($proposedValue instanceof ormDocument)) {
return parent::HasAValue($proposedValue);
}
// Empty file (no content, just a filename) are supported since PR {@link https://github.com/Combodo/combodo-email-synchro/pull/17}, so we check for both empty content and empty filename to determine that a document has no value
return utils::IsNotNullOrEmptyString($proposedValue->GetData()) && utils::IsNotNullOrEmptyString($proposedValue->GetFileName());
}
}
/**
@@ -9266,6 +9383,17 @@ class AttributeStopWatch extends AttributeDefinition
return $sRet;
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
// A stopwatch always has a value
return true;
}
}
/**
@@ -9751,6 +9879,19 @@ class AttributeOneWayPassword extends AttributeDefinition implements iAttributeN
return '*****';
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
// Protection against wrong value type
if (false === ($proposedValue instanceof ormPassword)) {
return parent::HasAValue($proposedValue);
}
return $proposedValue->IsEmpty() !== false;
}
}
// Indexed array having two dimensions
@@ -9800,6 +9941,15 @@ class AttributeTable extends AttributeDBField
return (count($proposedValue) == 0);
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
return count($proposedValue) > 0;
}
public function GetEditValue($sValue, $oHostObj = null)
{
return '';
@@ -10321,6 +10471,18 @@ abstract class AttributeSet extends AttributeDBFieldVoid
return $proposedValue->Count() == 0;
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
if (false === ($proposedValue instanceof ormSet)) {
return parent::HasAValue($proposedValue);
}
return $proposedValue->Count() > 0;
}
/**
* To be overloaded for localized enums
*
@@ -13035,6 +13197,21 @@ class AttributeCustomFields extends AttributeDefinition
return $bEquals;
}
/**
* @inheritDoc
*/
public function HasAValue($proposedValue): bool
{
// Protection against wrong value type
if (false === ($proposedValue instanceof ormCustomFieldsValue)) {
return parent::HasAValue($proposedValue);
}
return count($proposedValue->GetValues()) > 0;
}
}
class AttributeArchiveFlag extends AttributeBoolean

View File

@@ -4080,6 +4080,20 @@ abstract class DBObject implements iDisplay
return $bSuccess;
}
/**
* @param string $sAttCode
*
* @return bool True if $sAttCode has an actual value set, false is the attribute remains "empty"
* @throws \ArchivedObjectException
* @throws \CoreException
* @since 3.0.3, 3.1.0 N°5784
*/
public function HasAValue(string $sAttCode): bool
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAttDef->HasAValue($this->Get($sAttCode));
}
/**
* Helper to recover the default value (aka when an object is being created)
* Suitable for use as a lifecycle action

View File

@@ -29,4 +29,148 @@ class AttributeDefinitionTest extends ItopDataTestCase {
$this->assertEquals(["status" => "ENUM('active','inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"],
$aImportColumns);
}
/**
* @dataProvider HasAValueProvider
* @covers AttributeDefinition::HasAValue
*
* @param $sObjectClass
* @param $sAttCode
* @param $sUpdateCode
* @param $bHasAValueInitially
* @param $bHasAValueOnceSet
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function testHasAValue($sObjectClass, $sAttCode, $sUpdateCode, $bHasAValueInitially, $bHasAValueOnceSet)
{
$oObject = MetaModel::NewObject($sObjectClass);
// Test attribute without a value yet
$this->assertEquals($bHasAValueInitially, $oObject->HasAValue($sAttCode));
eval($sUpdateCode);
// Test attribute once a value has been set
$this->assertEquals($bHasAValueOnceSet, $oObject->HasAValue($sAttCode));
}
public function HasAValueProvider(): array
{
// Note: This is test is not great as we are datamodel dependent and don't have a class with all the attribute types
return [
'AttributeDashboard' => [
'Organization',
'overview',
'',
false,
false,
],
'AttributeLinkedSet' => [
'UserRequest',
'workorders_list',
<<<PHP
/** @var \ormLinkSet \$ormLinkset */
\$ormLinkset = \$oObject->Get('workorders_list');
\$ormLinkset->AddItem(MetaModel::NewObject('WorkOrder', []));
\$oObject->Set('workorders_list', \$ormLinkset);
PHP,
false,
true,
],
'AttributeLinkedSetIndirect' => [
'UserRequest',
'contacts_list',
<<<PHP
/** @var \ormLinkSet \$ormLinkset */
\$ormLinkset = \$oObject->Get('contacts_list');
\$ormLinkset->AddItem(MetaModel::NewObject('Person', []));
\$oObject->Set('contacts_list', \$ormLinkset);
PHP,
false,
true,
],
'AttributeInteger' => [
'SLT',
'value',
<<<PHP
\$oObject->Set('value', 100);
PHP,
false,
true,
],
'AttributeDecimal' => [
'PhysicalInterface',
'speed',
<<<PHP
\$oObject->Set('speed', 1024.5);
PHP,
false,
true,
],
'AttributeString' => [
'UserRequest',
'title',
<<<PHP
\$oObject->Set('title', 'Some title');
PHP,
false,
true,
],
'AttributeObjectKey' => [
'Attachment',
'item_id',
<<<PHP
\$oObject->Set('item_id', 12);
PHP,
false,
true,
],
'AttributeExternalKey' => [
'UserRequest',
'org_id',
<<<PHP
\$oObject->Set('org_id', 3);
PHP,
false,
true,
],
'AttributeBlob' => [
'DocumentFile',
'file',
<<<PHP
\$oObject->Set('file', new ormDocument('something', 'text/plain', 'something.txt'));
PHP,
false,
true,
],
'AttributeStopWatch' => [
'UserRequest',
'tto',
'',
true,
true,
],
'AttributeSubItem' => [
'UserRequest',
'tto_escalation_deadline',
'',
true,
true,
],
'AttributeOneWayPassword' => [
'UserLocal',
'password',
<<<PHP
$/** @var \ormPassword \$ormPassword */
\$ormPassword = new ormPassword('somehash', 'somesalt');
\$oObject->Set('password', \$ormPassword);
PHP,
false,
true,
],
];
}
}