Quellcode durchsuchen

Fixed Trac #292: enums can now be null (if allowed) !

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@910 a333f486-631f-4898-b8df-5754b55c2be0
dflaven vor 14 Jahren
Ursprung
Commit
38e1d43d3c

+ 1 - 1
application/cmdbabstract.class.inc.php

@@ -1133,7 +1133,7 @@ EOF
 							// Few choices, use a normal 'select'
 							// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
 							$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" id=\"$iId\">\n";
-							$sHTMLValue .= "<option value=\"0\">".Dict::S('UI:SelectOne')."</option>\n";
+							$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
 							foreach($aAllowedValues as $key => $display_value)
 							{
 								if ((count($aAllowedValues) == 1) && $bMandatory )

+ 123 - 2
core/attributedef.class.inc.php

@@ -576,6 +576,106 @@ class AttributeInteger extends AttributeDBField
 }
 
 /**
+ * Map a decimal value column (suitable for financial computations) to an attribute
+ * internally in PHP such numbers are represented as string. Should you want to perform
+ * a calculation on them, it is recommended to use the BC Math functions in order to
+ * retain the precision
+ *
+ * @package     iTopORM
+ */
+class AttributeDecimal extends AttributeDBField
+{
+	static protected function ListExpectedParams()
+	{
+		return array_merge(parent::ListExpectedParams(), array('digits', 'decimals' /* including precision */));
+	}
+
+	public function GetType() {return "Decimal";}
+	public function GetTypeDesc() {return "Decimal value (could be negative)";}
+	public function GetEditClass() {return "String";}
+	protected function GetSQLCol() {return "DECIMAL(".$this->Get('digits').",".$this->Get('decimals').")";}
+	
+	public function GetValidationPattern()
+	{
+		$iNbDigits = $this->Get('digits');
+		$iPrecision = $this->Get('decimals');
+		$iNbIntegerDigits = $iNbDigits - $iPrecision - 1; // -1 because the first digit is treated separately in the pattern below
+		return "^[-+]?[0-9]\d{0,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
+	}
+
+	public function GetBasicFilterOperators()
+	{
+		return array(
+			"!="=>"differs from",
+			"="=>"equals",
+			">"=>"greater (strict) than",
+			">="=>"greater than",
+			"<"=>"less (strict) than",
+			"<="=>"less than",
+			"in"=>"in"
+		);
+	}
+	public function GetBasicFilterLooseOperator()
+	{
+		// Unless we implement an "equals approximately..." or "same order of magnitude"
+		return "=";
+	}
+
+	public function GetBasicFilterSQLExpr($sOpCode, $value)
+	{
+		$sQValue = CMDBSource::Quote($value);
+		switch ($sOpCode)
+		{
+		case '!=':
+			return $this->GetSQLExpr()." != $sQValue";
+			break;
+		case '>':
+			return $this->GetSQLExpr()." > $sQValue";
+			break;
+		case '>=':
+			return $this->GetSQLExpr()." >= $sQValue";
+			break;
+		case '<':
+			return $this->GetSQLExpr()." < $sQValue";
+			break;
+		case '<=':
+			return $this->GetSQLExpr()." <= $sQValue";
+			break;
+		case 'in':
+			if (!is_array($value)) throw new CoreException("Expected an array for argument value (sOpCode='$sOpCode')");
+			return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; 
+			break;
+
+		case '=':
+		default:
+			return $this->GetSQLExpr()." = \"$value\"";
+		}
+	} 
+
+	public function GetNullValue()
+	{
+		return null;
+	} 
+	public function IsNull($proposedValue)
+	{
+		return is_null($proposedValue);
+	} 
+
+	public function MakeRealValue($proposedValue)
+	{
+		if (is_null($proposedValue)) return null;
+		if ($proposedValue == '') return null;
+		return (string)$proposedValue;
+	}
+
+	public function ScalarToSQL($value)
+	{
+		assert(is_null($value) || preg_match('/'.$this->GetValidationPattern().'/', $value));
+		return (string)$value; // treated as a string
+	}
+}
+
+/**
  * Map a boolean column to an attribute 
  *
  * @package     iTopORM
@@ -1133,7 +1233,15 @@ class AttributeEnum extends AttributeString
 
 	public function GetAsHTML($sValue)
 	{
-		$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
+		if (is_null($sValue))
+		{
+			// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label		
+			$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, Dict::S('Enum:Undefined'));
+		}
+		else
+		{
+			$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
+		}
 		$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', $sValue);
 		// later, we could imagine a detailed description in the title
 		return "<span title=\"$sDescription\">".parent::GetAsHtml($sLabel)."</span>";
@@ -1155,7 +1263,19 @@ class AttributeEnum extends AttributeString
 			$aLocalizedValues[$sKey] = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sKey, $sKey);
 		}
   		return $aLocalizedValues;
-  }
+  	}
+  	
+  	/**
+  	 * Processes the input value to align it with the values supported
+  	 * by this type of attribute. In this case: turns empty strings into nulls
+  	 * @param mixed $proposedValue The value to be set for the attribute
+  	 * @return mixed The actual value that will be set
+  	 */
+	public function MakeRealValue($proposedValue)
+	{
+		if ($proposedValue == '') return null;
+		return parent::MakeRealValue($proposedValue);
+	}
 }
 
 /**
@@ -1599,6 +1719,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
 	public function MakeRealValue($proposedValue)
 	{
 		if (is_null($proposedValue)) return 0;
+		if ($proposedValue === '') return 0;
 		if (MetaModel::IsValidObject($proposedValue)) return $proposedValue->GetKey();
 		return (int)$proposedValue;
 	}

+ 2 - 0
dictionaries/de.dictionary.itop.ui.php

@@ -876,6 +876,8 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
 	'Portal:Button:CloseTicket' => 'Dieses Ticket schließen',
 	'Portal:EnterYourCommentsOnTicket' => 'Geben Sie einen Kommentar zur Lösung dieses Tickets ein:',
 	'Portal:ErrorNoContactForThisUser' => 'Fehler: der derzeitige Benutzer wurde nicht einem Kontakt oder einer Person zugewiesen. Bitte kontaktieren Sie Ihren Administrator.',
+
+	'Enum:Undefined' => 'Nicht definiert',
 ));
 
 

+ 2 - 0
dictionaries/dictionary.itop.ui.php

@@ -861,6 +861,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
 	'Portal:Button:CloseTicket' => 'Close this ticket',
 	'Portal:EnterYourCommentsOnTicket' => 'Enter your comments about the resolution of this ticket:',
 	'Portal:ErrorNoContactForThisUser' => 'Error: the current user is not associated with a Contact/Person. Please contact your administrator.',
+	
+	'Enum:Undefined' => 'Undefined',
 ));
 
 

+ 2 - 0
dictionaries/es_cr.dictionary.itop.ui.php

@@ -837,6 +837,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
 	'UI:Deadline_Days_Hours_Minutes' => '%1$dd %2$dh %3$dmin',
 	'UI:Help' => 'Ayuda',
 	'UI:PasswordConfirm' => '(Confirm)',
+
+	'Enum:Undefined' => 'Undefined',
 ));
 
 ?>

+ 2 - 0
dictionaries/fr.dictionary.itop.ui.php

@@ -870,6 +870,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
 	'Portal:Button:CloseTicket' => 'Clôre cette requête',
 	'Portal:EnterYourCommentsOnTicket' => 'Vos commentaires à propos du traitement de cette requête:',
 	'Portal:ErrorNoContactForThisUser' => 'Erreur: l\'utilisateur courant n\'est pas associé à une Personne/Contact. Contactez votre administrateur.',
+
+	'Enum:Undefined' => 'Non défini',
 ));
 
 ?>